iff2html working
|
@ -141,9 +141,9 @@ endif()
|
|||
add_subdirectory(formats)
|
||||
add_subdirectory(libgldemo)
|
||||
add_subdirectory(libvitaboy)
|
||||
add_subdirectory(tools)
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(renderdemo_ray)
|
||||
add_subdirectory(rlgldemo)
|
||||
endif()
|
||||
|
||||
|
|
5
library/tools/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
add_subdirectory(FARDive)
|
||||
add_subdirectory(hitutils)
|
||||
add_subdirectory(iff2html)
|
||||
add_subdirectory(rtti-reader)
|
||||
add_subdirectory(tsoscan)
|
18
library/tools/FARDive/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(FARDive)
|
||||
|
||||
if(WIN32)
|
||||
set(FARDIVE_SOURCES
|
||||
windows/common.cpp
|
||||
windows/Interaction.cpp
|
||||
windows/MainWindow.cpp
|
||||
windows/ReadPNGIcon.cpp
|
||||
windows/Resource.rc
|
||||
windows/Startup.cpp
|
||||
windows/Dialog/AddToArchive.cpp
|
||||
windows/Dialog/NewArchive.cpp
|
||||
)
|
||||
include_directories(${LIBPNG_INCLUDE})
|
||||
add_executable(FARDive WIN32 ${FARDIVE_SOURCES})
|
||||
target_link_libraries(FARDive ole32 uxtheme FileHandler_shared)
|
||||
endif()
|
16
library/tools/FARDive/FARDive.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "version.hpp"
|
||||
|
||||
namespace Archive {
|
||||
extern wchar_t Path[1024], Filename[1024];
|
||||
|
||||
extern bool IsOpen;
|
||||
extern bool IsModified;
|
||||
|
||||
bool Add(const wchar_t * Path);
|
||||
bool Close();
|
||||
bool Open();
|
||||
bool PopulateEntries();
|
||||
bool Save();
|
||||
bool SaveAs();
|
||||
bool SetWorkspace();
|
||||
}
|
After Width: | Height: | Size: 409 B |
BIN
library/tools/FARDive/resources/icons/applications-other.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
library/tools/FARDive/resources/icons/audio-x-generic.png
Normal file
After Width: | Height: | Size: 614 B |
BIN
library/tools/FARDive/resources/icons/document-new.png
Normal file
After Width: | Height: | Size: 405 B |
BIN
library/tools/FARDive/resources/icons/document-open.png
Normal file
After Width: | Height: | Size: 598 B |
BIN
library/tools/FARDive/resources/icons/document-properties.png
Normal file
After Width: | Height: | Size: 346 B |
BIN
library/tools/FARDive/resources/icons/document-save-as.png
Normal file
After Width: | Height: | Size: 616 B |
BIN
library/tools/FARDive/resources/icons/document-save.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
library/tools/FARDive/resources/icons/edit-clear.png
Normal file
After Width: | Height: | Size: 682 B |
BIN
library/tools/FARDive/resources/icons/edit-copy.png
Normal file
After Width: | Height: | Size: 404 B |
BIN
library/tools/FARDive/resources/icons/edit-find.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
library/tools/FARDive/resources/icons/edit-select-all.png
Normal file
After Width: | Height: | Size: 328 B |
BIN
library/tools/FARDive/resources/icons/emblem-unreadable.png
Normal file
After Width: | Height: | Size: 396 B |
BIN
library/tools/FARDive/resources/icons/go-first.png
Normal file
After Width: | Height: | Size: 607 B |
BIN
library/tools/FARDive/resources/icons/go-jump.png
Normal file
After Width: | Height: | Size: 591 B |
BIN
library/tools/FARDive/resources/icons/go-last.png
Normal file
After Width: | Height: | Size: 610 B |
BIN
library/tools/FARDive/resources/icons/help-about.png
Normal file
After Width: | Height: | Size: 596 B |
BIN
library/tools/FARDive/resources/icons/info.bmp
Normal file
After Width: | Height: | Size: 822 B |
BIN
library/tools/FARDive/resources/icons/internet-web-browser.png
Normal file
After Width: | Height: | Size: 758 B |
BIN
library/tools/FARDive/resources/icons/list-add.png
Normal file
After Width: | Height: | Size: 217 B |
BIN
library/tools/FARDive/resources/icons/list-remove.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
library/tools/FARDive/resources/icons/mail-send-receive.png
Normal file
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 512 B |
BIN
library/tools/FARDive/resources/icons/package-x-generic.png
Normal file
After Width: | Height: | Size: 469 B |
BIN
library/tools/FARDive/resources/icons/preferences-desktop.png
Normal file
After Width: | Height: | Size: 384 B |
After Width: | Height: | Size: 351 B |
BIN
library/tools/FARDive/resources/icons/system-file-manager.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
library/tools/FARDive/resources/icons/system-log-out.png
Normal file
After Width: | Height: | Size: 725 B |
BIN
library/tools/FARDive/resources/icons/utilities-terminal.png
Normal file
After Width: | Height: | Size: 610 B |
108
library/tools/FARDive/resources/optimize.bat
Normal file
|
@ -0,0 +1,108 @@
|
|||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 accessories-text-editor.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 accessories-text-editor.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k accessories-text-editor.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 applications-other.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 applications-other.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k applications-other.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 audio-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 audio-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k audio-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 document-new.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 document-new.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k document-new.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 document-open.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 document-open.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k document-open.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 document-properties.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 document-properties.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k document-properties.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 document-save-as.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 document-save-as.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k document-save-as.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 document-save.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 document-save.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k document-save.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 edit-clear.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 edit-clear.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k edit-clear.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 edit-copy.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 edit-copy.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k edit-copy.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 edit-find.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 edit-find.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k edit-find.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 edit-select-all.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 edit-select-all.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k edit-select-all.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 emblem-unreadable.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 emblem-unreadable.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k emblem-unreadable.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 go-first.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 go-first.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k go-first.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 go-jump.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 go-jump.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k go-jump.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 go-last.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 go-last.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k go-last.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 internet-web-browser.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 internet-web-browser.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k internet-web-browser.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 list-add.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 list-add.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k list-add.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 list-remove.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 list-remove.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k list-remove.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 mail-send-receive.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 mail-send-receive.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k mail-send-receive.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 package-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 package-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k package-x-generic.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 package-x-generic-selected.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 package-x-generic-selected.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k package-x-generic-selected.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 preferences-desktop.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 preferences-desktop.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k preferences-desktop.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 preferences-system-windows.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 preferences-system-windows.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k preferences-system-windows.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 system-file-manager.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 system-file-manager.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k system-file-manager.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 system-log-out.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 system-log-out.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw1k system-log-out.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw256 utilities-terminal.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zw512 utilities-terminal.png
|
||||
optipng -zc1-9 -zm1-9 -zs0-3 -f0-5 -i0 -zwutilities-terminal.png
|
||||
advpng -z -4 accessories-text-editor.png
|
||||
advpng -z -4 applications-other.png
|
||||
advpng -z -4 audio-x-generic.png
|
||||
advpng -z -4 document-new.png
|
||||
advpng -z -4 document-open.png
|
||||
advpng -z -4 document-properties.png
|
||||
advpng -z -4 document-save-as.png
|
||||
advpng -z -4 document-save.png
|
||||
advpng -z -4 emblem-unreadable.png
|
||||
advpng -z -4 edit-clear.png
|
||||
advpng -z -4 edit-copy.png
|
||||
advpng -z -4 edit-find.png
|
||||
advpng -z -4 edit-select-all.png
|
||||
advpng -z -4 go-first.png
|
||||
advpng -z -4 go-jump.png
|
||||
advpng -z -4 go-last.png
|
||||
advpng -z -4 internet-web-browser.png
|
||||
advpng -z -4 list-add.png
|
||||
advpng -z -4 list-remove.png
|
||||
advpng -z -4 mail-send-receive.png
|
||||
advpng -z -4 package-x-generic-selected.png
|
||||
advpng -z -4 package-x-generic.png
|
||||
advpng -z -4 preferences-desktop.png
|
||||
advpng -z -4 preferences-system-windows.png
|
||||
advpng -z -4 system-file-manager.png
|
||||
advpng -z -4 system-log-out.png
|
||||
advpng -z -4 utilities-terminal.png
|
|
@ -0,0 +1 @@
|
|||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df"/></dependentAssembly></dependency></assembly>
|
BIN
library/tools/FARDive/resources/windows/FARDive.ico
Normal file
After Width: | Height: | Size: 23 KiB |
17
library/tools/FARDive/version.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#define FD_VERSION_A 0
|
||||
#define FD_VERSION_B 0
|
||||
#define FD_VERSION_C 1
|
||||
#define FD_REVISION 1
|
||||
|
||||
//You don't have to touch the following
|
||||
#define xstr(x) str(x)
|
||||
#define str(x) #x //Yes, double levels is required. See <http://gcc.gnu.org/onlinedocs/cpp/Stringification.html>
|
||||
#define FDVERSION L"" \
|
||||
xstr(FD_VERSION_A) \
|
||||
L"." \
|
||||
xstr(FD_VERSION_B) \
|
||||
L"." \
|
||||
xstr(FD_VERSION_C) \
|
||||
L" (rev. " \
|
||||
xstr(FD_REVISION) \
|
||||
L")"
|
53
library/tools/FARDive/windows/Dialog/AddToArchive.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "../Windows.hpp"
|
||||
#include "../GUI.hpp"
|
||||
|
||||
namespace AddToArchive {
|
||||
|
||||
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
||||
switch (message){
|
||||
case WM_INITDIALOG: {
|
||||
CenterDialog(hDlg);
|
||||
|
||||
HWND hBox = GetDlgItem(hDlg, IDC_A2A_FILE);
|
||||
SendMessage(hBox, EM_SETLIMITTEXT, 1023, 0);
|
||||
hBox = GetDlgItem(hDlg, IDC_A2A_FILENAME);
|
||||
SendMessage(hBox, EM_SETLIMITTEXT, 1023, 0);
|
||||
|
||||
if(lParam){
|
||||
HWND hBox = GetDlgItem(hDlg, IDC_A2A_FILE);
|
||||
SetWindowText(hBox, (wchar_t*) lParam);
|
||||
hBox = GetDlgItem(hDlg, IDC_A2A_FILENAME);
|
||||
wchar_t Filename[1024];
|
||||
GetFileTitle((wchar_t*) lParam, Filename, 1024);
|
||||
SetWindowText(hBox, Filename);
|
||||
}
|
||||
|
||||
} return TRUE;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam)){
|
||||
case IDC_A2A_BROWSE: {
|
||||
wchar_t Path[1024] = L"", Filename[1024] = L"";
|
||||
ofn.hwndOwner = hDlg;
|
||||
ofn.lpstrFilter = FILTER_FILES;
|
||||
ofn.lpstrCustomFilter = ArchiveAddFilter;
|
||||
ofn.lpstrFile = Path;
|
||||
ofn.lpstrFileTitle = Filename;
|
||||
ofn.Flags = OFN_DONTADDTORECENT | OFN_HIDEREADONLY;
|
||||
if(GetOpenFileName(&ofn)){
|
||||
SetWindowText(GetDlgItem(hDlg, IDC_A2A_FILE), Path);
|
||||
SetWindowText(GetDlgItem(hDlg, IDC_A2A_FILENAME), Filename);
|
||||
}
|
||||
} break;
|
||||
case IDOK:
|
||||
EndDialog(hDlg, true);
|
||||
break;
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg, false);
|
||||
} break;
|
||||
case WM_CLOSE:
|
||||
EndDialog(hDlg, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
118
library/tools/FARDive/windows/Dialog/NewArchive.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "../Windows.hpp"
|
||||
#include "../GUI.hpp"
|
||||
|
||||
#ifndef TTI_INFO_LARGE
|
||||
#define TTI_INFO_LARGE 4
|
||||
#endif
|
||||
|
||||
namespace NewArchive {
|
||||
|
||||
enum {TYPE_FAR, TYPE_DBPF};
|
||||
void SetType(HWND hDlg, int type){
|
||||
for(int i=IDC_NA_FARVERSIONTEXT; i<=IDC_NA_FARVERSION; i++)
|
||||
EnableWindow(GetDlgItem(hDlg, i), type==TYPE_FAR);
|
||||
for(int i=IDC_NA_DBPFVERSIONTEXT; i<=IDC_NA_DBPFCOMPRESS; i++)
|
||||
EnableWindow(GetDlgItem(hDlg, i), type==TYPE_DBPF);
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
|
||||
switch (message){
|
||||
case WM_INITDIALOG: {
|
||||
CenterDialog(hDlg);
|
||||
|
||||
//Fill the drop-down boxes
|
||||
HWND hBox = GetDlgItem(hDlg, IDC_NA_TYPE);
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"FAR");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"DBPF");
|
||||
SendMessage(hBox, CB_SETCURSEL, 0, 0);
|
||||
hBox = GetDlgItem(hDlg, IDC_NA_FARVERSION);
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"1a");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"1b");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"3");
|
||||
SendMessage(hBox, CB_SETCURSEL, 0, 0);
|
||||
hBox = GetDlgItem(hDlg, IDC_NA_DBPFVERSION);
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"1.0");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"1.1");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"2.0");
|
||||
SendMessage(hBox, CB_SETCURSEL, 0, 0);
|
||||
hBox = GetDlgItem(hDlg, IDC_NA_INDEXVERSION);
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"7.0");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"7.1");
|
||||
SendMessage(hBox, CB_INSERTSTRING, -1, (LPARAM) L"3.0");
|
||||
SendMessage(hBox, CB_SETCURSEL, 0, 0);
|
||||
|
||||
//Create the tooltips
|
||||
HWND FARInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL),
|
||||
DBPFInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
hDlg, NULL, hInst, NULL);
|
||||
|
||||
TOOLINFO tinfo = {
|
||||
sizeof(TOOLINFO), //cbSize
|
||||
TTF_IDISHWND | TTF_SUBCLASS, //uFlags
|
||||
hDlg, //hwnd
|
||||
0, //uId
|
||||
NULL, //rect
|
||||
0 //hinst
|
||||
};
|
||||
|
||||
tinfo.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_NA_FARINFO);
|
||||
tinfo.lpszText = (wchar_t*)
|
||||
L"FAR version 1a is found in The Sims 1.\r\n\r\n"
|
||||
L"Version 1b appears to be a mistake, in which it was intended to take on the version number 2.\r\n\r\n"
|
||||
L"1b and 3 are both found exclusively in The Sims Online.";
|
||||
SendMessage(FARInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
|
||||
SendMessage(FARInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"FAR version");
|
||||
SendMessage(FARInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(FARInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 12000);
|
||||
tinfo.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_NA_DBPFINFO);
|
||||
tinfo.lpszText = (wchar_t*)
|
||||
L"DBPF version numbers can be shortened to the form a.b;ix,y, where "
|
||||
L"a.b is the Archive version and x.y is the Index version.\r\n\r\n"
|
||||
L"DBPF 1.0;i7.0 is found in The Sims Online and SimCity 4.\r\n\r\n"
|
||||
L"1.0;i7.0 and 1.1;i7.1 are found in The Sims 2.\r\n\r\n"
|
||||
L"2.0;i3.0 is found in Spore.";
|
||||
SendMessage(DBPFInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
|
||||
SendMessage(DBPFInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"DBPF version");
|
||||
SendMessage(DBPFInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
|
||||
SendMessage(DBPFInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 20000);
|
||||
|
||||
SetType(hDlg, TYPE_FAR);
|
||||
} return TRUE;
|
||||
case WM_CTLCOLORSTATIC:
|
||||
if((HWND) lParam == GetDlgItem(hDlg, IDC_NA_TYPETEXT)){
|
||||
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
|
||||
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam)){
|
||||
case IDC_NA_TYPE:
|
||||
if(HIWORD(wParam) == CBN_SELCHANGE)
|
||||
SetType(hDlg, SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0));
|
||||
break;
|
||||
case IDOK:
|
||||
Archive::IsOpen = true;
|
||||
Archive::IsModified = true;
|
||||
|
||||
Archive::Path[0] = '\0'; //No actual path
|
||||
wcscpy(Archive::Filename, L"Untitled");
|
||||
Archive::SetWorkspace();
|
||||
|
||||
EndDialog(hDlg, 0);
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg, 0);
|
||||
} break;
|
||||
case WM_CLOSE:
|
||||
EndDialog(hDlg, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
59
library/tools/FARDive/windows/GUI.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
extern HINSTANCE hInst;
|
||||
|
||||
extern HMENU hMenu, listmenu;
|
||||
extern HDC hDC;
|
||||
extern OPENFILENAME ofn;
|
||||
extern unsigned int statusbarheight;
|
||||
|
||||
extern HBITMAP PNGIcon[MENUICONS];
|
||||
enum {
|
||||
BMP_FILE_NEW,
|
||||
BMP_FILE_OPEN,
|
||||
BMP_FILE_SAVE,
|
||||
BMP_FILE_SAVEAS,
|
||||
BMP_FILE_ADD,
|
||||
BMP_FILE_EXPORTALL,
|
||||
BMP_FILE_EXPORTSELECTED,
|
||||
BMP_FILE_CHANGETYPE,
|
||||
BMP_FILE_CLOSE,
|
||||
BMP_FILE_EXIT,
|
||||
BMP_EDIT_DUPLICATE,
|
||||
BMP_EDIT_REMOVE,
|
||||
BMP_EDIT_RENAME,
|
||||
BMP_EDIT_PROPERTIES,
|
||||
BMP_EDIT_CONTENTS,
|
||||
BMP_EDIT_FIND,
|
||||
BMP_EDIT_FINDNEXT,
|
||||
BMP_EDIT_FINDPREVIOUS,
|
||||
BMP_EDIT_MATCHES,
|
||||
BMP_EDIT_GOTO,
|
||||
BMP_EDIT_PREFERENCES,
|
||||
BMP_TOOLS_RECOMPRESS,
|
||||
BMP_TOOLS_RESORT,
|
||||
BMP_TOOLS_REMOVEHOLES,
|
||||
BMP_TOOLS_BATCH,
|
||||
BMP_HELP_HOWTOUSE
|
||||
};
|
||||
|
||||
static const wchar_t FILTER_ARCHIVES_FILES[] =
|
||||
L"All supported archives\0*.far;*.dbpf;*.dat;*.package\0"
|
||||
L"FAR (*.far, *.dat, *.package)\0*.far;*.dat;*.package\0"
|
||||
L"DBPF (*.dbpf, *.dat, *.package)\0*.dbpf;*.dat;*.package\0"
|
||||
L"All Files\0*.*\0\0";
|
||||
|
||||
static const wchar_t FILTER_ARCHIVES_ONLY[] =
|
||||
L"All supported archives\0*.far;*.dbpf;*.dat;*.package\0"
|
||||
L"FAR (*.far, *.dat, *.package)\0*.far;*.dat;*.package\0"
|
||||
L"DBPF (*.dbpf, *.dat, *.package)\0*.dbpf;*.dat;*.package\0"
|
||||
L"All Files\0*.*\0\0";
|
||||
|
||||
static const wchar_t FILTER_FILES[] =
|
||||
L"All Files\0*.*\0\0";
|
||||
|
||||
extern wchar_t ArchiveOpenFilter[128], ArchiveAddFilter[128], ArchiveSaveFilter[128];
|
||||
|
||||
//Controls
|
||||
extern HWND hWnd, statusbar, hList;
|
||||
|
||||
void CenterDialog(HWND hDlg);
|
||||
HBITMAP ReadPNGIcon(int ID);
|
174
library/tools/FARDive/windows/Interaction.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include "Windows.hpp"
|
||||
#include <uxtheme.h>
|
||||
#include "GUI.hpp"
|
||||
|
||||
namespace Archive {
|
||||
|
||||
wchar_t Path[1024], Filename[1024];
|
||||
|
||||
bool IsOpen = false;
|
||||
bool IsModified;
|
||||
|
||||
bool Add(const wchar_t * Path){
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Close(){
|
||||
if(!Archive::IsOpen) return true;
|
||||
|
||||
if(Archive::IsModified){
|
||||
//Ask for consent
|
||||
int result = MessageBox(hWnd, L"Save changes?", L"Save changes?", MB_YESNOCANCEL);
|
||||
if(result == IDYES){
|
||||
if(!Archive::Save())
|
||||
return false;
|
||||
}else if(result != IDNO)
|
||||
return false;
|
||||
}
|
||||
|
||||
//Close the workspace
|
||||
|
||||
Archive::IsOpen = false;
|
||||
|
||||
SetWindowText(hWnd, L"FARDive");
|
||||
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) L"");
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fState = MFS_DISABLED;
|
||||
|
||||
int DisableItems[] = {
|
||||
ID_FILE_SAVE,
|
||||
ID_FILE_SAVEAS,
|
||||
ID_FILE_ADD,
|
||||
ID_FILE_EXPORTALL,
|
||||
ID_FILE_EXPORTSELECTED,
|
||||
ID_FILE_CHANGETYPE,
|
||||
ID_FILE_CLOSE,
|
||||
ID_EDIT_DUPLICATE,
|
||||
ID_EDIT_REMOVE,
|
||||
ID_EDIT_RENAME,
|
||||
ID_EDIT_PROPERTIES,
|
||||
ID_EDIT_CONTENTS,
|
||||
ID_EDIT_FIND,
|
||||
ID_EDIT_FINDNEXT,
|
||||
ID_EDIT_FINDPREVIOUS,
|
||||
ID_EDIT_MATCHES,
|
||||
ID_EDIT_GOTO,
|
||||
ID_TOOLS_RECOMPRESS,
|
||||
ID_TOOLS_RESORT,
|
||||
ID_TOOLS_REMOVETRASH,
|
||||
0};
|
||||
for(int i=0; DisableItems[i]; i++)
|
||||
SetMenuItemInfo(hMenu, DisableItems[i], FALSE, &mii);
|
||||
|
||||
DestroyWindow(hList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Open(){
|
||||
if(!Archive::Close()) return false;
|
||||
|
||||
GetFileTitle(Archive::Path, Archive::Filename, 1024);
|
||||
|
||||
Archive::IsOpen = true;
|
||||
Archive::IsModified = false;
|
||||
|
||||
SetWorkspace();
|
||||
}
|
||||
|
||||
bool PopulateEntries(){
|
||||
unsigned EntryCount = 1;
|
||||
LVITEM item;
|
||||
memset(&item, 0x00, sizeof(LVITEM));
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = 0;
|
||||
item.pszText = (LPTSTR) L"Test";
|
||||
SendMessage(hList, LVM_SETITEMCOUNT, EntryCount, LVSICF_NOSCROLL);
|
||||
SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM) &item);
|
||||
|
||||
wchar_t buffer[17];
|
||||
wsprintf(buffer, L"%u file%s", EntryCount, (EntryCount == 1) ? L"" : L"s");
|
||||
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) buffer);
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fState = (EntryCount > 0) ? MFS_ENABLED : MFS_DISABLED;
|
||||
SetMenuItemInfo(hMenu, ID_FILE_EXPORTALL, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_FIND, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_FINDNEXT, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_FINDPREVIOUS, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_MATCHES, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_GOTO, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_TOOLS_RECOMPRESS, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_TOOLS_RESORT, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_TOOLS_REMOVETRASH, FALSE, &mii);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Save(){
|
||||
if(!Archive::IsModified) return true;
|
||||
if(Path[0] == '\0'){ //No path because we're dealing with a newly created archive
|
||||
return SaveAs();
|
||||
}
|
||||
|
||||
Archive::IsModified = false;
|
||||
wchar_t WindowTitle[1024+10];
|
||||
wsprintf(WindowTitle, L"%s%s - FARDive", Archive::Filename, L"");
|
||||
SetWindowText(hWnd, WindowTitle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveAs(){
|
||||
wchar_t OldPath[1024], OldFilename[1024];
|
||||
//Backup old settings
|
||||
wcscpy(OldPath, Archive::Path);
|
||||
wcscpy(OldFilename, Archive::Filename);
|
||||
|
||||
ofn.hwndOwner = hWnd;
|
||||
ofn.lpstrFilter = FILTER_ARCHIVES_ONLY;
|
||||
ofn.lpstrCustomFilter = ArchiveSaveFilter;
|
||||
ofn.lpstrFile = Path;
|
||||
ofn.lpstrFileTitle = Filename;
|
||||
ofn.Flags = OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
if(GetSaveFileName(&ofn) && Save())
|
||||
return true;
|
||||
|
||||
//Restore old settings
|
||||
wcscpy(Archive::Path, OldPath);
|
||||
wcscpy(Archive::Filename, OldFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SetWorkspace(){
|
||||
wchar_t WindowTitle[1024+11];
|
||||
wsprintf(WindowTitle, L"%s%s - FARDive", Archive::Filename, Archive::IsModified ? L"*" : L"");
|
||||
SetWindowText(hWnd, WindowTitle);
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fState = MFS_ENABLED;
|
||||
|
||||
SetMenuItemInfo(hMenu, ID_FILE_SAVE, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_FILE_SAVEAS, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_FILE_ADD, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_FILE_CHANGETYPE, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_FILE_CLOSE, FALSE, &mii);
|
||||
|
||||
RECT ClientRect;
|
||||
GetClientRect(hWnd, &ClientRect);
|
||||
hList = CreateWindowEx(WS_EX_CLIENTEDGE | LVS_EX_DOUBLEBUFFER | WS_EX_COMPOSITED, WC_LISTVIEW, NULL, LVS_LIST | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE,
|
||||
5, 5, 192, ClientRect.bottom-statusbarheight-10, hWnd, NULL, NULL, NULL);
|
||||
SetWindowTheme(hList, L"Explorer", NULL);
|
||||
|
||||
PopulateEntries();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
167
library/tools/FARDive/windows/MainWindow.cpp
Normal file
|
@ -0,0 +1,167 @@
|
|||
#include "Windows.hpp"
|
||||
#include "GUI.hpp"
|
||||
|
||||
HWND hList;
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(message){
|
||||
|
||||
case WM_SIZE:
|
||||
SendMessage(statusbar, WM_SIZE, 0, 0);
|
||||
|
||||
if(Archive::IsOpen)
|
||||
SetWindowPos(hList, 0, 0, 0, 192, HIWORD(lParam)-statusbarheight-10,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOOWNERZORDER);
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case ID_FILE_NEW:
|
||||
if(Archive::Close())
|
||||
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_NEWARCHIVE), hWnd, NewArchive::DlgProc, NULL);
|
||||
break;
|
||||
case ID_FILE_OPEN:
|
||||
if(!Archive::Close()) break;
|
||||
ofn.hwndOwner = hWnd;
|
||||
ofn.lpstrFilter = FILTER_ARCHIVES_FILES;
|
||||
ofn.lpstrCustomFilter = ArchiveOpenFilter;
|
||||
ofn.lpstrFile = Archive::Path;
|
||||
ofn.lpstrFileTitle = NULL;
|
||||
ofn.Flags = OFN_DONTADDTORECENT | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
if(GetOpenFileName(&ofn))
|
||||
Archive::Open();
|
||||
break;
|
||||
case ID_FILE_SAVE:
|
||||
Archive::Save();
|
||||
break;
|
||||
case ID_FILE_SAVEAS:
|
||||
Archive::SaveAs();
|
||||
break;
|
||||
case ID_FILE_ADD: {
|
||||
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ADDTOARCHIVE_FAR1), hWnd, AddToArchive::DlgProc, 0);
|
||||
} break;
|
||||
case ID_HELP_ABOUT:
|
||||
MessageBox(hWnd, L"FARDive version " FDVERSION
|
||||
L"\r\n\r\nThis is an alpha release of FARDive. The About box is not yet complete.\r\n\r\n"
|
||||
L"Don't worry, file writing will not be implemented until it is guaranteed stable.\r\n\r\n"
|
||||
L"Saving the archive through File -> Save (or Save as) will not actually "
|
||||
L"take place until we reach that point.\r\n\r\n"
|
||||
L"=-----=\r\n\r\n"
|
||||
L"FARDive - Copyright (c) 2011 Fatbag <X-Fi6@phppoll.org>\r\n\r\n"
|
||||
L"Permission to use, copy, modify, and/or distribute this software for any "
|
||||
L"purpose with or without fee is hereby granted, provided that the above "
|
||||
L"copyright notice and this permission notice appear in all copies.\r\n\r\n"
|
||||
L"THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES "
|
||||
L"WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF "
|
||||
L"MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR "
|
||||
L"ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES "
|
||||
L"WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN "
|
||||
L"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF "
|
||||
L"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r\n\r\n", L"About", MB_OK);
|
||||
break;
|
||||
case ID_FILE_CLOSE:
|
||||
Archive::Close();
|
||||
break;
|
||||
case ID_FILE_EXIT:
|
||||
if(Archive::Close())
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NOTIFY: {
|
||||
NMHDR *nmhdr = (NMHDR*) lParam;
|
||||
if(nmhdr->hwndFrom == hList){
|
||||
switch(nmhdr->code){
|
||||
case LVN_ITEMCHANGED: {
|
||||
unsigned selected = SendMessage(hList, LVM_GETSELECTEDCOUNT, 0, 0);
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_STATE;
|
||||
|
||||
mii.fState = (selected > 0) ? MFS_ENABLED : MFS_DISABLED;
|
||||
SetMenuItemInfo(hMenu, ID_FILE_EXPORTSELECTED, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_DUPLICATE, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_REMOVE, FALSE, &mii);
|
||||
|
||||
mii.fState = (selected == 1) ? MFS_ENABLED : MFS_DISABLED;
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_RENAME, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_PROPERTIES, FALSE, &mii);
|
||||
SetMenuItemInfo(hMenu, ID_EDIT_CONTENTS, FALSE, &mii);
|
||||
} break;
|
||||
|
||||
case NM_RCLICK: {
|
||||
unsigned selected = SendMessage(hList, LVM_GETSELECTEDCOUNT, 0, 0);
|
||||
|
||||
if(listmenu) DestroyMenu(listmenu);
|
||||
listmenu = CreatePopupMenu();
|
||||
|
||||
#define AddSeparator() \
|
||||
mii.fMask = MIIM_TYPE; \
|
||||
InsertMenuItem(listmenu, ++position, TRUE, &mii); \
|
||||
mii.fMask = MIIM_ID | MIIM_STRING | MIIM_BITMAP
|
||||
#define AddItem(x,y,z) \
|
||||
mii.wID = x; \
|
||||
mii.dwTypeData = (wchar_t*) y; \
|
||||
mii.hbmpItem = PNGIcon[z]; \
|
||||
InsertMenuItem(listmenu, ++position, TRUE, &mii)
|
||||
|
||||
unsigned position = 0;
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_ID | MIIM_STRING | MIIM_BITMAP;
|
||||
mii.fType = MFT_SEPARATOR;
|
||||
|
||||
AddItem(ID_LISTMENU_ADD, L"A&dd to archive", BMP_FILE_ADD);
|
||||
|
||||
if(selected > 0){
|
||||
AddSeparator();
|
||||
AddItem(ID_LISTMENU_EXPORTSELECTED, L"Export &selected...", BMP_FILE_EXPORTSELECTED);
|
||||
AddItem(ID_LISTMENU_DUPLICATE, L"D&uplicate", BMP_EDIT_DUPLICATE);
|
||||
AddItem(ID_LISTMENU_REMOVE, L"&Remove", BMP_EDIT_REMOVE);
|
||||
if(selected == 1){
|
||||
AddSeparator();
|
||||
AddItem(ID_LISTMENU_RENAME, L"Re&name", BMP_EDIT_RENAME);
|
||||
AddItem(ID_LISTMENU_PROPERTIES, L"Change pr&operties...", BMP_EDIT_PROPERTIES);
|
||||
AddItem(ID_LISTMENU_CONTENTS, L"Change file &contents...", BMP_EDIT_CONTENTS);
|
||||
}
|
||||
}
|
||||
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
TrackPopupMenu(listmenu, TPM_RIGHTBUTTON, p.x, p.y, 0, hWnd, NULL);
|
||||
PostMessage(hWnd, WM_NULL, 0, 0);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_DROPFILES:
|
||||
if(!Archive::IsOpen){
|
||||
//Open as an archive
|
||||
unsigned strlen = DragQueryFile((HDROP) wParam, 0, Archive::Path, 1024);
|
||||
DragFinish((HDROP) wParam);
|
||||
if(strlen)
|
||||
Archive::Open();
|
||||
}else{
|
||||
//Add to the current archive
|
||||
wchar_t EntryPath[1024];
|
||||
unsigned strlen = DragQueryFile((HDROP) wParam, 0, EntryPath, 1024);
|
||||
DragFinish((HDROP) wParam);
|
||||
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ADDTOARCHIVE_FAR1), hWnd, AddToArchive::DlgProc, (LPARAM) EntryPath);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
if(Archive::Close())
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
67
library/tools/FARDive/windows/ReadPNGIcon.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include <windows.h>
|
||||
#include <png.h>
|
||||
|
||||
extern HDC hDC;
|
||||
|
||||
char * buffer;
|
||||
|
||||
void user_read_data(png_structp, png_bytep data, png_size_t length){
|
||||
memcpy(data, buffer, length);
|
||||
buffer += length;
|
||||
}
|
||||
|
||||
HBITMAP ReadPNGIcon(int ID){
|
||||
HRSRC resource = FindResource(NULL, MAKEINTRESOURCE(ID), RT_RCDATA);
|
||||
buffer = (char *) LockResource(LoadResource(NULL, resource));
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_set_read_fn(png_ptr, NULL, user_read_data);
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 width, height;
|
||||
int bit_depth, color_type;
|
||||
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
|
||||
if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
else if(color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_MASK_PALETTE)
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
|
||||
png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
|
||||
png_set_bgr(png_ptr);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
BITMAPINFOHEADER bmi = {
|
||||
sizeof(BITMAPINFOHEADER), //biSize
|
||||
width, //biWidth
|
||||
height, //biHeight
|
||||
1, //biPlanes
|
||||
32, //biBitCount
|
||||
BI_RGB, //biCompression
|
||||
width*height*4, //biSizeImage
|
||||
0, //biXPelsPerMeter
|
||||
0, //biYPelsPerMeter
|
||||
0, //biClrUsed
|
||||
0 //biClrImportant
|
||||
};
|
||||
|
||||
unsigned char *buffer;
|
||||
png_bytep row_pointers[height];
|
||||
HBITMAP hBmp = CreateDIBSection(hDC, (BITMAPINFO*) &bmi, DIB_RGB_COLORS, (void**) &buffer, NULL, 0);
|
||||
for(unsigned i=0; i<height; i++)
|
||||
row_pointers[i] = buffer + width*4*(height-i-1);
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
//Convert from BGRA to pre-multiplied BGRA (PBGRA)
|
||||
//Description here: http://msdn.microsoft.com/en-us/library/ee719797%28VS.85%29.aspx
|
||||
for(unsigned i=0; i<width*height*4; i+=4){
|
||||
unsigned alpha = buffer[i+3];
|
||||
int j;
|
||||
for(j=0; j<3; j++)
|
||||
buffer[i+j] = (char)((unsigned) buffer[i+j]*alpha/255);
|
||||
}
|
||||
|
||||
return hBmp;
|
||||
}
|
78
library/tools/FARDive/windows/Startup.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "Windows.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include <png.h>
|
||||
|
||||
HBITMAP PNGIcon[MENUICONS];
|
||||
|
||||
HINSTANCE hInst;
|
||||
|
||||
HWND hWnd, statusbar;
|
||||
HDC hDC;
|
||||
unsigned int statusbarheight;
|
||||
|
||||
OPENFILENAME ofn;
|
||||
|
||||
wchar_t ArchiveOpenFilter[128] = L"", ArchiveAddFilter[128] = L"", ArchiveSaveFilter[128] = L"";
|
||||
|
||||
HMENU hMenu, listmenu = 0;
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int){
|
||||
hInst = hInstance;
|
||||
|
||||
WNDCLASS wc = {
|
||||
CS_HREDRAW | CS_VREDRAW, //style
|
||||
WndProc, //lpfnWndProc
|
||||
0, //cbClsExtra
|
||||
0, //cbWndExtra
|
||||
hInst, //hInstance
|
||||
(HICON) LoadImage(hInst, MAKEINTRESOURCE(IDI_FARDIVE), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR), //hIcon
|
||||
(HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE), //hCursor
|
||||
(HBRUSH) (COLOR_MENU+1), //hbrBackground
|
||||
MAKEINTRESOURCE(IDM_FARDIVE), //lpszMenuName
|
||||
L"F" //lpszClassName
|
||||
};
|
||||
RegisterClass(&wc);
|
||||
|
||||
hWnd = CreateWindowEx(WS_EX_ACCEPTFILES | WS_EX_COMPOSITED, L"F", L"FARDive",
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 616, 616, 0, 0, hInst, 0);
|
||||
statusbar = CreateWindowEx(WS_EX_COMPOSITED, L"msctls_statusbar32", NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, 0, hInst, 0);
|
||||
RECT rect;
|
||||
GetWindowRect(statusbar, &rect);
|
||||
statusbarheight = rect.bottom - rect.top;
|
||||
|
||||
hDC = GetDC(NULL);
|
||||
hMenu = GetMenu(hWnd);
|
||||
|
||||
memset(&ofn, sizeof(ofn), 0x00);
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
ofn.nMaxCustFilter = 128;
|
||||
ofn.nMaxFile = 1024;
|
||||
ofn.nMaxFileTitle = 1024;
|
||||
ofn.lpstrDefExt = L"dat";
|
||||
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFO);
|
||||
mii.fMask = MIIM_BITMAP;
|
||||
|
||||
static const short iconmenulist[] = {
|
||||
2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107,
|
||||
2108, 2109, 2200, 2201, 2202, 2203, 2204, 2205,
|
||||
2206, 2207, 2208, 2209, 2210, 2300, 2301, 2302,
|
||||
2303, 2400, 2401
|
||||
};
|
||||
|
||||
for(unsigned i=0; i<MENUICONS; i++){
|
||||
int ID = iconmenulist[i];
|
||||
mii.hbmpItem = PNGIcon[i] = ReadPNGIcon(ID);
|
||||
SetMenuItemInfo(hMenu, ID-1000, FALSE, &mii);
|
||||
}
|
||||
|
||||
HACCEL acceltable = LoadAccelerators(hInst, MAKEINTRESOURCE(ID_ACCELERATOR));
|
||||
MSG msg;
|
||||
while(GetMessage(&msg, NULL, 0, 0)){
|
||||
TranslateAccelerator(hWnd, acceltable, &msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
12
library/tools/FARDive/windows/Windows.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#define UNICODE
|
||||
#define WINVER 0x0600
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "../FARDive.hpp"
|
||||
#include "resource.hpp"
|
||||
|
||||
#define DefineDialog(x) namespace x {INT_PTR CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
DefineDialog(AddToArchive);
|
||||
DefineDialog(NewArchive);
|
11
library/tools/FARDive/windows/common.cpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include "Windows.hpp"
|
||||
#include "GUI.hpp"
|
||||
|
||||
void CenterDialog(HWND hDlg){
|
||||
RECT parent, child;
|
||||
GetWindowRect(hWnd, &parent);
|
||||
GetWindowRect(hDlg, &child);
|
||||
int x = (parent.right + parent.left - child.right + child.left)/2,
|
||||
y = (parent.bottom + parent.top - child.bottom + child.top)/2;
|
||||
SetWindowPos(hDlg, 0, x, y, 0, 0, SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
102
library/tools/FARDive/windows/resource.hpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
#define ID_VERSIONINFO 1
|
||||
#define ID_MANIFEST 1 //Not a typo
|
||||
#define IDI_FARDIVE 2
|
||||
|
||||
#define ID_ACCELERATOR 100
|
||||
#define IDB_INFO 101
|
||||
|
||||
#define IDC_STATIC -1
|
||||
|
||||
#define IDM_FARDIVE 1000
|
||||
#define ID_FILE_NEW 1100
|
||||
#define ID_FILE_OPEN 1101
|
||||
#define ID_FILE_SAVE 1102
|
||||
#define ID_FILE_SAVEAS 1103
|
||||
#define ID_FILE_ADD 1104
|
||||
#define ID_FILE_EXPORTALL 1105
|
||||
#define ID_FILE_EXPORTSELECTED 1106
|
||||
#define ID_FILE_CHANGETYPE 1107
|
||||
#define ID_FILE_CLOSE 1108
|
||||
#define ID_FILE_EXIT 1109
|
||||
#define ID_EDIT_DUPLICATE 1200
|
||||
#define ID_EDIT_REMOVE 1201
|
||||
#define ID_EDIT_RENAME 1202
|
||||
#define ID_EDIT_PROPERTIES 1203
|
||||
#define ID_EDIT_CONTENTS 1204
|
||||
#define ID_EDIT_FIND 1205
|
||||
#define ID_EDIT_FINDNEXT 1206
|
||||
#define ID_EDIT_FINDPREVIOUS 1207
|
||||
#define ID_EDIT_MATCHES 1208
|
||||
#define ID_EDIT_GOTO 1209
|
||||
#define ID_EDIT_PREFERENCES 1210
|
||||
#define ID_TOOLS_RECOMPRESS 1300
|
||||
#define ID_TOOLS_RESORT 1301
|
||||
#define ID_TOOLS_REMOVETRASH 1302
|
||||
#define ID_TOOLS_BATCH 1303
|
||||
#define ID_HELP_WEBSITE 1400
|
||||
#define ID_HELP_ABOUT 1401
|
||||
|
||||
#define MENUICONS 27
|
||||
#define IDI_FILE_NEW 2100
|
||||
#define IDI_FILE_OPEN 2101
|
||||
#define IDI_FILE_SAVE 2102
|
||||
#define IDI_FILE_SAVEAS 2103
|
||||
#define IDI_FILE_ADD 2104
|
||||
#define IDI_FILE_EXPORTALL 2105
|
||||
#define IDI_FILE_EXPORTSELECTED 2106
|
||||
#define IDI_FILE_CHANGETYPE 2107
|
||||
#define IDI_FILE_CLOSE 2108
|
||||
#define IDI_FILE_EXIT 2109
|
||||
#define IDI_EDIT_DUPLICATE 2200
|
||||
#define IDI_EDIT_REMOVE 2201
|
||||
#define IDI_EDIT_RENAME 2202
|
||||
#define IDI_EDIT_PROPERTIES 2203
|
||||
#define IDI_EDIT_CONTENTS 2204
|
||||
#define IDI_EDIT_FIND 2205
|
||||
#define IDI_EDIT_FINDNEXT 2206
|
||||
#define IDI_EDIT_FINDPREVIOUS 2207
|
||||
#define IDI_EDIT_MATCHES 2208
|
||||
#define IDI_EDIT_GOTO 2209
|
||||
#define IDI_EDIT_PREFERENCES 2210
|
||||
#define IDI_TOOLS_RECOMPRESS 2300
|
||||
#define IDI_TOOLS_RESORT 2301
|
||||
#define IDI_TOOLS_REMOVEHOLES 2302
|
||||
#define IDI_TOOLS_BATCH 2303
|
||||
#define IDI_HELP_WEBSITE 2400
|
||||
#define IDI_HELP_ABOUT 2401
|
||||
|
||||
//Right-click menu items
|
||||
#define ID_LISTMENU_ADD 3100
|
||||
#define ID_LISTMENU_EXPORTSELECTED 3101
|
||||
#define ID_LISTMENU_DUPLICATE 3102
|
||||
#define ID_LISTMENU_REMOVE 3103
|
||||
#define ID_LISTMENU_RENAME 3104
|
||||
#define ID_LISTMENU_PROPERTIES 3105
|
||||
#define ID_LISTMENU_CONTENTS 3106
|
||||
|
||||
//Dialogs
|
||||
#define IDD_NEWARCHIVE 3000
|
||||
#define IDD_ADDTOARCHIVE_FAR1 3001
|
||||
#define IDD_ADDTOARCHIVE_FAR3 3002
|
||||
#define IDD_ADDTOARCHIVE_DBPF 3003
|
||||
|
||||
//New Archive
|
||||
#define IDC_NA_TYPETEXT 4000
|
||||
#define IDC_NA_TYPE 4001
|
||||
#define IDC_NA_FARINFO 4002
|
||||
#define IDC_NA_DBPFINFO 4003
|
||||
#define IDC_NA_FARVERSIONTEXT 4004
|
||||
#define IDC_NA_FARVERSION 4005
|
||||
#define IDC_NA_DBPFVERSIONTEXT 4006
|
||||
#define IDC_NA_DBPFVERSION 4007
|
||||
#define IDC_NA_INDEXVERSIONTEXT 4008
|
||||
#define IDC_NA_INDEXVERSION 4009
|
||||
#define IDC_NA_DBPFCOMPRESS 4010
|
||||
|
||||
//Add to Archive
|
||||
#define IDC_A2A_FILE 4000
|
||||
#define IDC_A2A_BROWSE 4001
|
||||
#define IDC_A2A_FILENAME 4002
|
||||
#define IDC_A2A_TYPEID 4003
|
||||
#define IDC_A2A_INSTANCEID 4004
|
||||
#define IDC_A2A_INSTANCEID2 4005
|
170
library/tools/FARDive/windows/resource.rc
Normal file
|
@ -0,0 +1,170 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "../version.hpp"
|
||||
#include "resource.hpp"
|
||||
|
||||
ID_MANIFEST RT_MANIFEST "../resources/Windows/FARDive.exe.manifest"
|
||||
IDI_FARDIVE ICON "../resources/Windows/FARDive.ico"
|
||||
|
||||
ID_VERSIONINFO VERSIONINFO
|
||||
FILEVERSION FD_VERSION_A,FD_VERSION_B,FD_VERSION_C,FD_REVISION
|
||||
PRODUCTVERSION FD_VERSION_A,FD_VERSION_B,FD_VERSION_C,FD_REVISION
|
||||
FILEOS 0x00040000L //Windows 32-bit+
|
||||
FILETYPE 1 //1 is exe, 2 is dll, and so on.
|
||||
//The list can be found at <http://msdn.microsoft.com/en-us/library/aa381058.aspx>
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Written by Fatbag."
|
||||
VALUE "FileDescription", "An interactive file browser for FAR/DBPF"
|
||||
VALUE "FileVersion", FDVERSION
|
||||
VALUE "InternalName", "FARDive"
|
||||
VALUE "LegalCopyright", "X11 license"
|
||||
VALUE "OriginalFilename", "FARDive.exe"
|
||||
VALUE "ProductName", "FARDive"
|
||||
VALUE "ProductVersion", FDVERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0409, 0x04B0
|
||||
END
|
||||
END
|
||||
|
||||
IDM_FARDIVE MENUEX
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&New...\tCtrl+N", ID_FILE_NEW
|
||||
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
|
||||
MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Save &As...", ID_FILE_SAVEAS, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "A&dd to archive...", ID_FILE_ADD, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Export a&ll...", ID_FILE_EXPORTALL, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Export s&elected...", ID_FILE_EXPORTSELECTED, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Change archive &type...", ID_FILE_CHANGETYPE, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Close archive\tCtrl+W", ID_FILE_CLOSE, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "E&xit", ID_FILE_EXIT
|
||||
END
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "&Duplicate\tCtrl+D", ID_EDIT_DUPLICATE, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "&Remove\tDel", ID_EDIT_REMOVE, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Re&name", ID_EDIT_RENAME, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "File pr&operties...", ID_EDIT_PROPERTIES, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Change file &contents...", ID_EDIT_CONTENTS, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Find...\tCtrl+F", ID_EDIT_FIND, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Find ne&xt\tF3", ID_EDIT_FINDNEXT, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Find pre&vious\tShift+F3", ID_EDIT_FINDPREVIOUS, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "&Show all matches", ID_EDIT_MATCHES, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "&Go to...\tCtrl+G", ID_EDIT_GOTO, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Preferences...", ID_EDIT_PREFERENCES
|
||||
END
|
||||
POPUP "&Tools"
|
||||
BEGIN
|
||||
MENUITEM "Re&compress...", ID_TOOLS_RECOMPRESS, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Re-&sort files...", ID_TOOLS_RESORT, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "Remove t&rash files...", ID_TOOLS_REMOVETRASH, MFT_STRING,MFS_GRAYED
|
||||
MENUITEM "&Batch processing...", ID_TOOLS_BATCH
|
||||
END
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "Visit &Website...", ID_HELP_WEBSITE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&About", ID_HELP_ABOUT
|
||||
END
|
||||
END
|
||||
|
||||
IDI_FILE_NEW RCDATA "../resources/icons/document-new.png"
|
||||
IDI_FILE_OPEN RCDATA "../resources/icons/document-open.png"
|
||||
IDI_FILE_SAVE RCDATA "../resources/icons/document-save.png"
|
||||
IDI_FILE_SAVEAS RCDATA "../resources/icons/document-save-as.png"
|
||||
IDI_FILE_ADD RCDATA "../resources/icons/list-add.png"
|
||||
IDI_FILE_EXPORTALL RCDATA "../resources/icons/package-x-generic.png"
|
||||
IDI_FILE_EXPORTSELECTED RCDATA "../resources/icons/package-x-generic-selected.png"
|
||||
IDI_FILE_CHANGETYPE RCDATA "../resources/icons/applications-other.png"
|
||||
IDI_FILE_CLOSE RCDATA "../resources/icons/emblem-unreadable.png"
|
||||
IDI_FILE_EXIT RCDATA "../resources/icons/system-log-out.png"
|
||||
IDI_EDIT_DUPLICATE RCDATA "../resources/icons/edit-copy.png"
|
||||
IDI_EDIT_REMOVE RCDATA "../resources/icons/list-remove.png"
|
||||
IDI_EDIT_RENAME RCDATA "../resources/icons/edit-select-all.png"
|
||||
IDI_EDIT_PROPERTIES RCDATA "../resources/icons/document-properties.png"
|
||||
IDI_EDIT_CONTENTS RCDATA "../resources/icons/accessories-text-editor.png"
|
||||
IDI_EDIT_FIND RCDATA "../resources/icons/edit-find.png"
|
||||
IDI_EDIT_FINDNEXT RCDATA "../resources/icons/go-last.png"
|
||||
IDI_EDIT_FINDPREVIOUS RCDATA "../resources/icons/go-first.png"
|
||||
IDI_EDIT_MATCHES RCDATA "../resources/icons/preferences-system-windows.png"
|
||||
IDI_EDIT_GOTO RCDATA "../resources/icons/go-jump.png"
|
||||
IDI_EDIT_PREFERENCES RCDATA "../resources/icons/preferences-desktop.png"
|
||||
IDI_TOOLS_RECOMPRESS RCDATA "../resources/icons/system-file-manager.png"
|
||||
IDI_TOOLS_RESORT RCDATA "../resources/icons/mail-send-receive.png"
|
||||
IDI_TOOLS_REMOVEHOLES RCDATA "../resources/icons/edit-clear.png"
|
||||
IDI_TOOLS_BATCH RCDATA "../resources/icons/utilities-terminal.png"
|
||||
IDI_HELP_WEBSITE RCDATA "../resources/icons/internet-web-browser.png"
|
||||
IDI_HELP_ABOUT RCDATA "../resources/icons/help-about.png"
|
||||
|
||||
IDB_INFO BITMAP "../resources/icons/info.bmp"
|
||||
|
||||
ID_ACCELERATOR ACCELERATORS
|
||||
BEGIN
|
||||
"^N", ID_FILE_NEW, ASCII
|
||||
"^O", ID_FILE_OPEN, ASCII
|
||||
"^S", ID_FILE_SAVE, ASCII
|
||||
"^W", ID_FILE_CLOSE, ASCII
|
||||
|
||||
"^D", ID_EDIT_DUPLICATE, ASCII
|
||||
"^F", ID_EDIT_FIND, ASCII
|
||||
VK_F3, ID_EDIT_FINDNEXT, VIRTKEY
|
||||
VK_F3, ID_EDIT_FINDPREVIOUS, SHIFT, VIRTKEY
|
||||
"^G", ID_EDIT_GOTO, ASCII
|
||||
END
|
||||
|
||||
IDD_NEWARCHIVE DIALOGEX 0, 0, 200, 161
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "New archive"
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "",IDC_STATIC,-2,-2,204,27,SS_WHITERECT | WS_BORDER
|
||||
RTEXT "Archive type:",IDC_NA_TYPETEXT,12,9,80,8
|
||||
COMBOBOX IDC_NA_TYPE,108,7,50,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "FAR options",IDC_STATIC,7,33,186,30
|
||||
RTEXT "Version:",IDC_NA_FARVERSIONTEXT,12,44,80,8
|
||||
COMBOBOX IDC_NA_FARVERSION,108,43,50,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL IDB_INFO,IDC_NA_FARINFO,"STATIC",SS_BITMAP | SS_NOTIFY | SS_REALSIZEIMAGE,164,44,11,10
|
||||
GROUPBOX "DBPF options",IDC_STATIC,7,71,186,62
|
||||
RTEXT "Archive Version:",IDC_NA_DBPFVERSIONTEXT,12,83,80,8
|
||||
COMBOBOX IDC_NA_DBPFVERSION,108,81,50,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Index Version:",IDC_NA_INDEXVERSIONTEXT,12,103,80,8
|
||||
COMBOBOX IDC_NA_INDEXVERSION,108,101,50,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL IDB_INFO,IDC_NA_DBPFINFO,"STATIC",SS_BITMAP | SS_NOTIFY | SS_REALSIZEIMAGE,164,92,11,10
|
||||
CHECKBOX "Use QFS compression",IDC_NA_DBPFCOMPRESS,12,118,100,10,BS_AUTOCHECKBOX | WS_TABSTOP
|
||||
DEFPUSHBUTTON "OK",IDOK,34,140,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,116,140,50,14
|
||||
END
|
||||
|
||||
IDD_ADDTOARCHIVE_FAR1 DIALOGEX 0, 0, 200, 149
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Add to archive"
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
GROUPBOX "Source",IDC_STATIC,7,7,186,30
|
||||
CTEXT "File:",IDC_STATIC,12,18,30,8
|
||||
EDITTEXT IDC_A2A_FILE,44,16,90,14,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "Browse...",IDC_A2A_BROWSE,138,16,50,14
|
||||
GROUPBOX "Attributes",IDC_STATIC,7,44,186,58
|
||||
CTEXT "File name:",IDC_STATIC,12,54,80,8
|
||||
EDITTEXT IDC_A2A_FILENAME,96,52,92,14,ES_AUTOHSCROLL
|
||||
CTEXT "Type ID:",IDC_STATIC,12,70,80,8
|
||||
EDITTEXT IDC_A2A_TYPEID,96,68,92,14,ES_AUTOHSCROLL
|
||||
CTEXT "Instance ID:",IDC_STATIC,12,86,80,8
|
||||
EDITTEXT IDC_A2A_INSTANCEID,96,84,92,14,ES_AUTOHSCROLL
|
||||
DEFPUSHBUTTON "OK",IDOK,34,128,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,116,128,50,14
|
||||
END
|
0
library/tools/Server GUI/CMakeLists.txt
Normal file
19
library/tools/TSOSimulatorClient/Readme.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
DLLs in The Sims Online (and also SimCity 4 and The Sims 2) use a special
|
||||
interface, based on Microsoft COM.
|
||||
|
||||
These DLLs each export exactly one function:
|
||||
void * GZDllGetGZCOMDirector(void)
|
||||
|
||||
This function creates and sets up a C++ object, with variables and member
|
||||
functions, and returns a pointer to that object. This is your standard
|
||||
C++ v-table.
|
||||
|
||||
TSOSimulatorClientD.dll is the most important DLL in the game. It implements
|
||||
the SimAntics virtual machine which executes all the objects in the game.
|
||||
In our situation, we need to figure out everything it does, because we lack
|
||||
any information regarding the SimAntics instruction set architecture.
|
||||
A text dump of this DLL is not nearly enough to find this. The files in the
|
||||
objectdata/globals folder are not nearly enough. The page on
|
||||
simtech.sourceforge.net documenting all they know about SimAntics is not
|
||||
nearly enough. We need to run this DLL in a disassembler and figure out the
|
||||
meaning of every opcode used in every behavior script of the game.
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
TSOEdithEditor - TSOEdithEditorD.dll injector
|
||||
TSOEdithEditor.cpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "TSOEdithEditor.hpp"
|
||||
|
||||
int main(){
|
||||
HMODULE dllmodule = LoadLibrary("TSOEdithEditorD.dll");
|
||||
if(dllmodule == NULL){
|
||||
printf("TSOEdithEditor: Error: Failed to load DLL \"TSOEdithEditorD.dll\".");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cTSOEdithEditorDCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cTSOEdithEditorDCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
if(GZDllGetGZCOMDirector == NULL){
|
||||
printf("TSOEdithEditor: Error: Failed to find GZDllGetGZCOMDirector() in TSOEdithEditorD.dll.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Calling GZDllGetGZCOMDirector() ...\n");
|
||||
cTSOEdithEditorDCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||
printf("TSOEdithEditor: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Edith);
|
||||
|
||||
while(true){
|
||||
char buffer[8];
|
||||
printf("\nCall a function (0, 1, 2, ...) or q to exit. ");
|
||||
//fgets(buffer, 8, stdin);
|
||||
//if(buffer[0] == 'q') break;
|
||||
//Edith->Object1.vtable5[atoi(buffer)]();
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Exiting.\n");
|
||||
FreeLibrary(dllmodule);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
TSOEdithEditor - TSOEdithEditorD.dll injector
|
||||
TSOEdithEditor.hpp - Copyright (c) 2012 Fatbag <X-Fi6@phppoll.org>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <basetyps.h>
|
||||
#pragma pack(0)
|
||||
|
||||
DECLARE_INTERFACE(cRZString)
|
||||
{
|
||||
void * vtable1_cRZString;
|
||||
char * mpBegin; //Pointer to beginning of string
|
||||
char * mpEnd; //Pointer to null terminator
|
||||
char * mpCapacity; //mpEnd + 1
|
||||
DWORD mAllocator; //0
|
||||
DWORD Zero1; //0
|
||||
};
|
||||
|
||||
struct stringstruct
|
||||
{
|
||||
DWORD StringID;
|
||||
DWORD Unknown;
|
||||
char * PointerToBuffer; //Buffer
|
||||
DWORD SizeOfBuffer; //256
|
||||
char Buffer[256];
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE(cEdithEditorCOMDirector)
|
||||
{
|
||||
void * vtable_1_cEdithEditorCOMDirector;
|
||||
void * vtable_2_cEdithEditorCOMDirector;
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
cRZString string;
|
||||
DWORD Zero5;
|
||||
DWORD Zero6;
|
||||
DWORD Zero7;
|
||||
DWORD Zero8;
|
||||
DWORD Zero9;
|
||||
DWORD Zero10;
|
||||
DWORD Zero11;
|
||||
void * ptr;
|
||||
DWORD Value1; //2
|
||||
DWORD Value2; //1
|
||||
float Value3; //1.0f
|
||||
DWORD Value4; //0x40000000
|
||||
DWORD Value5; //2
|
||||
DWORD Value6; //0
|
||||
DWORD Value7; //1
|
||||
DWORD Value8; //0
|
||||
stringstruct string0; //StringID:0, Unknown:40, value:"index"
|
||||
stringstruct string1; //StringID:1, Unknown:40, value:"value"
|
||||
stringstruct string2; //StringID:2, Unknown:150, value:"Name"
|
||||
stringstruct string3; //StringID:3, Unknown:200, value:"Description"
|
||||
DWORD Value9; //0
|
||||
DWORD Value10; //0
|
||||
stringstruct string4; //StringID:0, Unknown:90, value:"Calling Tree"
|
||||
stringstruct string5; //StringID:1, Unknown:86, value:"Type"
|
||||
stringstruct string6; //StringID:2, Unknown:83, value:"Title"
|
||||
stringstruct string7; //StringID:3, Unknown:65, value:"Yes"
|
||||
stringstruct string8; //StringID:4, Unknown:65, value:"No"
|
||||
stringstruct string9; //StringID:5, Unknown:65, value:"Cancel"
|
||||
stringstruct string10; //StringID:6, Unknown:300, value:"Message"
|
||||
stringstruct string11; //StringID:7, Unknown:45, value:"Tree ID"
|
||||
stringstruct string12; //StringID:8, Unknown:50, value:"Node #"
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE(cTSOEdithEditorDCOMDirector)
|
||||
{
|
||||
void * vtable1_cTSOEdithEditorDCOMDirector;
|
||||
void * vtable2_cTSOEdithEditorDCOMDirector;
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
cRZString String1;
|
||||
DWORD Zero5;
|
||||
DWORD Zero6;
|
||||
cEdithEditorCOMDirector ** memptr_1;
|
||||
void ** memptr_2;
|
||||
void ** memptr_3; //Same as memptr_2
|
||||
DWORD Zero7;
|
||||
DWORD Zero8;
|
||||
void * dllptr_4_100B5834; //CMemoryException TD
|
||||
DWORD Value1; //1
|
||||
DWORD Value2; //0
|
||||
float Value3; //1.0f
|
||||
DWORD Value4; //0x40000000
|
||||
DWORD Value5; //0
|
||||
DWORD Value6; //0
|
||||
DWORD Value7; //1
|
||||
cRZString String2;
|
||||
cRZString String3;
|
||||
cRZString String4;
|
||||
cRZString String5;
|
||||
cRZString String6;
|
||||
cRZString String7;
|
||||
cRZString String8;
|
||||
cRZString String9;
|
||||
DWORD Zero9;
|
||||
DWORD Zero10;
|
||||
DWORD Zero11;
|
||||
DWORD Zero12;
|
||||
DWORD Zero13;
|
||||
DWORD Zero14;
|
||||
DWORD Zero15;
|
||||
cRZString String10;
|
||||
cRZString String11;
|
||||
cRZString String12;
|
||||
cRZString String13;
|
||||
cRZString String14;
|
||||
DWORD Zero16;
|
||||
DWORD Zero17;
|
||||
DWORD Zero18;
|
||||
DWORD Zero19;
|
||||
DWORD Zero20;
|
||||
cRZString String15;
|
||||
cRZString String16;
|
||||
cRZString String17;
|
||||
cRZString String18;
|
||||
cRZString String19;
|
||||
cRZString String20;
|
||||
cRZString String21;
|
||||
cRZString String22;
|
||||
cRZString String23;
|
||||
cRZString String24;
|
||||
cRZString String25;
|
||||
cRZString String26;
|
||||
cRZString String27;
|
||||
cRZString String28;
|
||||
cRZString String29;
|
||||
cRZString String30;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOEdithEditor.exe TSOEdithEditor.cpp -mconsole
|
46
library/tools/TSOSimulatorClient/TSOSimulatorClient.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
TSOSimulatorClient - TSOSimulatorClientD.dll injector
|
||||
TSOSimulatorClient.cpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include "TSOSimulatorClient.hpp"
|
||||
|
||||
int main(){
|
||||
HMODULE dllmodule = LoadLibrary("TSOSimulatorClientD.dll");
|
||||
if(dllmodule == NULL){
|
||||
printf("TSOSimulatorClient: Error: Failed to load DLL \"TSOSimulatorClientD.dll\".");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cTSOSimulatorClientDCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cTSOSimulatorClientDCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
if(GZDllGetGZCOMDirector == NULL){
|
||||
printf("TSOSimulatorClient: Error: Failed to find GZDllGetGZCOMDirector() in TSOSimulatorClientD.dll.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("TSOSimulatorClient: Calling GZDllGetGZCOMDirector() ...\n");
|
||||
cTSOSimulatorClientDCOMDirector * Simulator = GZDllGetGZCOMDirector();
|
||||
printf("TSOSimulatorClient: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Simulator);
|
||||
|
||||
printf("%s\n%s\n%s\n", Simulator->String1.Strings1[0], Simulator->String1.Strings2[0], Simulator->String1.Strings3[0]);
|
||||
|
||||
printf("TSOSimulatorClient: Exiting.\n");
|
||||
FreeLibrary(dllmodule);
|
||||
return 0;
|
||||
}
|
70
library/tools/TSOSimulatorClient/TSOSimulatorClient.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
TSOSimulatorClient - TSOSimulatorClientD.dll injector
|
||||
TSOSimulatorClient.hpp - Copyright (c) 2012 Fatbag <X-Fi6@phppoll.org>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <basetyps.h>
|
||||
#pragma pack(0)
|
||||
|
||||
DECLARE_INTERFACE(cRZString)
|
||||
{
|
||||
//Base classes: cRZString, std::char_traits, ?$_String_base@DV?$__default_alloc_template@$00$0A@@std@@@std, cIGZString, cIGZUnknown
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
void * vtable5;
|
||||
char ** Strings1;
|
||||
char ** Strings2;
|
||||
char ** Strings3;
|
||||
DWORD Zero3;
|
||||
DWORD Zero4;
|
||||
DWORD Zero5;
|
||||
void ** Pointer1; //12 bytes
|
||||
void ** Pointer2; //4 bytes
|
||||
void ** Pointer3;
|
||||
DWORD Flags;
|
||||
DWORD * Pointer4; //4 bytes
|
||||
void * Pointer5;
|
||||
void * Pointer6;
|
||||
DWORD Unknown11;
|
||||
DWORD Unknown12;
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE(cTSOSimulatorClientDCOMDirector)
|
||||
{
|
||||
//Base classes: cTSOSimulatorClientDCOMDirector, cRZCOMDllDirector, cIGZCOMDirector, cIGZUnknown, cIGZFrameWorkHooks, cIGZUnknown
|
||||
void * vtable2;
|
||||
void * vtable1;
|
||||
cRZString String1;
|
||||
void * vtable4;
|
||||
void * vtable3;
|
||||
cRZString String2;
|
||||
cRZString String3;
|
||||
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
DWORD Zero3;
|
||||
DWORD Zero4;
|
||||
DWORD Zero5;
|
||||
DWORD Zero6;
|
||||
DWORD Zero7;
|
||||
DWORD Zero8;
|
||||
DWORD Zero9;
|
||||
DWORD Zero10;
|
||||
DWORD Unknown1;
|
||||
DWORD Pointer1;
|
||||
DWORD Pointer2;
|
||||
DWORD Zero11;
|
||||
};
|
1
library/tools/TSOSimulatorClient/compile.bat
Normal file
|
@ -0,0 +1 @@
|
|||
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOSimulatorClient.exe TSOSimulatorClient.cpp -mconsole
|
106
library/tools/TSOSimulatorClient/memory map.txt
Normal file
|
@ -0,0 +1,106 @@
|
|||
CPU Dump
|
||||
Address Hex dump
|
||||
10102AF8 C4 61 0D 10|94 61 0D 10|00 00 00 00|00 00 00 00| 0
|
||||
10102B08 08 7A 0D 10|F8 30 3D 00|F8 30 3D 00|00 31 3D 00| 4
|
||||
10102B18 00 00 00 00|00 00 00 00|00 00 00 00|70 3B 3D 00| 8
|
||||
10102B28 7C 3B 3D 00|80 3B 3D 00|10 10 10 00|E0 32 3D 00| 12
|
||||
10102B38 E4 35 3D 00|E4 35 3D 00|00 00 00 00|01 00 00 00| 16
|
||||
10102B48 A4 62 0D 10|78 62 0D 10|00 00 00 00|00 00 00 00| 20
|
||||
10102B58 08 7A 0D 10|10 31 3D 00|10 31 3D 00|18 31 3D 00| 24
|
||||
10102B68 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| 28
|
||||
10102B78 00 00 00 00|00 00 00 00|10 10 10 00|58 3C 3D 00| 32
|
||||
10102B88 5C 3F 3D 00|5C 3F 3D 00|0D 00 00 00|01 00 00 00| 36
|
||||
10102B98 00 00 00 00|00 00 00 00|08 7A 0D 10|08 09 3D 00| 40
|
||||
10102BA8 1D 09 3D 00|1E 09 3D 00|00 00 00 00|00 00 00 00| 44
|
||||
10102BB8 00 00 00 00|18 31 3D 00|80 3B 3D 00|88 0A 3D 00| 48
|
||||
10102BC8 A8 2D 3D 00|00 00 00 00|00 00 00 00|00 00 00 00| 52
|
||||
10102BD8 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| 56
|
||||
10102BE8 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| 60
|
||||
10102BF8 00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| 64
|
||||
10102C08 10 0C 00 00|B0 3B 3D 00|40 3C 3D 00|00 00 00 00| 68
|
||||
|
||||
Offset: Meaning
|
||||
0: Pointer to v-table 2 - 100D61C4
|
||||
1: Pointer to v-table 1 - 100D6194
|
||||
|
||||
2: 0
|
||||
3: 0
|
||||
4: Pointer to v-table 5 - 100D7A08
|
||||
5: Pointer
|
||||
6: Pointer
|
||||
7: Pointer
|
||||
8: 0
|
||||
9: 0
|
||||
10: 0
|
||||
11: Pointer
|
||||
12: Pointer
|
||||
13: Pointer
|
||||
14: Flags? - 0x00101010
|
||||
15: Pointer
|
||||
16: Pointer
|
||||
17: Pointer
|
||||
18: 0
|
||||
19: 1
|
||||
|
||||
20: Pointer to v-table 4 - 100D62A4
|
||||
21: Pointer to v-table 3 - 100D6278
|
||||
|
||||
22: 0
|
||||
23: 0
|
||||
24: Pointer to v-table 5 - 100D7A08
|
||||
25: Pointer
|
||||
26: Pointer
|
||||
27: Pointer
|
||||
28: 0
|
||||
29: 0
|
||||
30: 0
|
||||
31: 0
|
||||
32: 0
|
||||
33: 0
|
||||
34: Flags? - 0x00101010
|
||||
35: Pointer
|
||||
36: Pointer
|
||||
37: Pointer
|
||||
38: 13
|
||||
39: 1
|
||||
|
||||
40: 0
|
||||
41: 0
|
||||
42: Pointer to v-table 5 - 100D7A08
|
||||
43: Pointer
|
||||
44: Pointer
|
||||
45: Pointer
|
||||
46: 0
|
||||
47: 0
|
||||
48: 0
|
||||
49: Pointer
|
||||
50: Pointer
|
||||
51: Pointer
|
||||
52: Pointer
|
||||
53: 0
|
||||
54: 0
|
||||
55: 0
|
||||
56: 0
|
||||
57: 0
|
||||
|
||||
58: 0
|
||||
59: 0
|
||||
60: 0
|
||||
61: 0
|
||||
62: 0
|
||||
63: 0
|
||||
64: 0
|
||||
65: 0
|
||||
66: 0
|
||||
67: 0
|
||||
68: 3088
|
||||
69: Pointer
|
||||
70: Pointer
|
||||
71: 0
|
||||
|
||||
5 v-tables:
|
||||
100D6194 (12 entries)
|
||||
100D61C4 (17 entries)
|
||||
100D6278 (11 entries)
|
||||
100D62A4 (344 entries)
|
||||
100D7A08 (695 entries)
|
0
library/tools/Translate Tool/CMakeLists.txt
Normal file
32
library/tools/Translate Tool/TranslateTool.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
The Sims Online Translation Tool - Graphical Translation Writer for TSO
|
||||
TranslateTool.hpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
namespace Translation {
|
||||
extern wchar_t Path[1024], Filename[1024];
|
||||
|
||||
extern bool IsOpen;
|
||||
extern bool IsModified;
|
||||
|
||||
bool Add(const wchar_t * Path);
|
||||
bool Close();
|
||||
bool Open();
|
||||
bool PopulateEntries();
|
||||
bool Save();
|
||||
bool SaveAs();
|
||||
bool SetWorkspace();
|
||||
}
|
18
library/tools/hitutils/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(hitutils)
|
||||
|
||||
set(HITDUMP_SOURCES
|
||||
hitdump.c
|
||||
)
|
||||
|
||||
set(HITASM_SOURCES
|
||||
hitasm.c
|
||||
)
|
||||
|
||||
set(HITLD_SOURCES
|
||||
hitld.c
|
||||
)
|
||||
|
||||
add_executable(hitdump ${HITDUMP_SOURCES})
|
||||
add_executable(hitasm ${HITASM_SOURCES})
|
||||
add_executable(hitld ${HITLD_SOURCES})
|
59
library/tools/hitutils/Design.txt
Normal file
|
@ -0,0 +1,59 @@
|
|||
1. Dumping
|
||||
|
||||
A HIT file is dumped by running this command:
|
||||
|
||||
$ hitdump -o example.txt example.hit
|
||||
|
||||
This will disassemble example.hit into example.txt using MakeTrax syntax.
|
||||
* Instructions, arguments, registers, and globals are rewritten using the mnemonics in
|
||||
example.hsm.
|
||||
* The disassembly is split into BINARY[] sections and logical addresses are defined names
|
||||
using the data provided by example.hsm, example.hot, example.evt, and the HIT symbol table.
|
||||
All user-created constants in example.hsm that begin with "tkd_" are interpreted by
|
||||
hitutils as track data.
|
||||
|
||||
|
||||
2. Reassembling
|
||||
|
||||
A source file is assembled into an intermediate object by running this command:
|
||||
|
||||
$ hitasm -o example.o example.txt
|
||||
|
||||
This will assemble example.txt into example.o according to MakeTrax syntax.
|
||||
* Instructions, arguments, and registers are interpreted using the mnemonics in example.hsm.
|
||||
* The logical addresses defined in example.hsm are ignored.
|
||||
|
||||
|
||||
3. Relinking into the game
|
||||
|
||||
Object files are relinked into the game by running this command:
|
||||
|
||||
$ hitld -o example.hit example1.o example2.o ...
|
||||
|
||||
This will link example1.o, example2.o, and so on into example.hit and reconstruct the
|
||||
relocation tables in example.hot and example.hsm.
|
||||
|
||||
|
||||
To clarify, the user cannot change the events signaled by objects without changing the
|
||||
SimAntics of each of those objects. The HIT subroutines invoked by those events, however, can
|
||||
be changed or swapped out quite easily.
|
||||
|
||||
|
||||
Appendix A. Address labeling strategies
|
||||
|
||||
In TSO, the HIT symbol table lists the logical address of each exported function, along with
|
||||
the Track File ID associated with it.
|
||||
|
||||
In TSO, the EVT file lists the name of each exported function, along with the Track File ID
|
||||
associated with it.
|
||||
|
||||
* The HIT file can be used to locate each exported function for placement in BINARY[] sections.
|
||||
* In the case of tsov2.hit, the HIT and EVT files can be used together to name these exported
|
||||
functions, seeing that the HSM file is not provided.
|
||||
|
||||
The HOT file lists all addresses that were labelled, along with the Track File ID associated
|
||||
with it, in the TrackData section. Because the HIT symbol table is not included in The Sims 1,
|
||||
the TrackData section can be used instead.
|
||||
|
||||
The HSM file lists the name of each labelled address, along with its logical address in the
|
||||
HIT file. (This is done with a Ctrl+F for "tkd_").
|
BIN
library/tools/hitutils/elf.dat
Normal file
120
library/tools/hitutils/elf.txt
Normal file
|
@ -0,0 +1,120 @@
|
|||
ELF Header:
|
||||
* e_ident:
|
||||
* Elf32_Word EI_MAG0: (7F 45 4C 46)
|
||||
* unsigned char EI_CLASS: ELFCLASS32 (01)
|
||||
* unsigned char EI_DATA: ELFDATA2LSB (01)
|
||||
* unsigned char EI_VERSION: EV_CURRENT (01)
|
||||
* unsigned char EI_PAD[9]: (00 00 00 00 00 00 00 00 00)
|
||||
* Elf32_Half e_type: ET_REL (01 00)
|
||||
* Elf32_Half e_machine: EM_NONE (00 00)
|
||||
* Elf32_Word e_version: EV_CURRENT (01 00 00 00)
|
||||
* Elf32_Addr e_entry: 0 (00 00 00 00)
|
||||
* Elf32_Off e_phoff: 0 (00 00 00 00)
|
||||
* Elf32_Off e_shoff: 64 (40 00 00 00)
|
||||
* Elf32_Word e_flags: 0x00000001 (01 00 00 00)
|
||||
* Elf32_Half e_ehsize: 52 (34 00)
|
||||
* Elf32_Half e_phentsize: 0 (00 00)
|
||||
* Elf32_Half e_phnum: 0 (00 00)
|
||||
* Elf32_Half e_shentsize: 40 (28 00)
|
||||
* Elf32_Half e_shnum: 6 (06 00)
|
||||
* Elf32_Half e_shstrndx: 2 (02 00)
|
||||
* unsigned char padding[12] = (00 00 00 00 00 00 00 00 00 00 00 00)
|
||||
|
||||
Section headers
|
||||
0 (""): All 0s
|
||||
1 (".text"):
|
||||
* Elf32_Word sh_name: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_type: SHT_PROGBITS (01 00 00 00)
|
||||
* Elf32_Word sh_flags: SHF_ALLOC | SHF_EXECINSTR (06 00 00 00)
|
||||
* Elf32_Addr sh_addr: 0 (00 00 00 00)
|
||||
* Elf32_Off sh_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_size: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_link: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_info: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_addralign: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_entsize: 0 (00 00 00 00)
|
||||
2 (".shstrtab"):
|
||||
* Elf32_Word sh_name: 7 (07 00 00 00)
|
||||
* Elf32_Word sh_type: SHT_STRTAB (03 00 00 00)
|
||||
* Elf32_Word sh_flags: 0 (00 00 00 00)
|
||||
* Elf32_Addr sh_addr: 0 (00 00 00 00)
|
||||
* Elf32_Off sh_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_size: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_link: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_info: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_addralign: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_entsize: 0 (00 00 00 00)
|
||||
3 (".symtab"):
|
||||
* Elf32_Word sh_name: 17 (11 00 00 00)
|
||||
* Elf32_Word sh_type: SHT_SYMTAB (02 00 00 00)
|
||||
* Elf32_Word sh_flags: 0 (00 00 00 00)
|
||||
* Elf32_Addr sh_addr: 0 (00 00 00 00)
|
||||
* Elf32_Off sh_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_size: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_link: 4 (04 00 00 00)
|
||||
* Elf32_Word sh_info: 5 (05 00 00 00)
|
||||
* Elf32_Word sh_addralign: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_entsize: 16 (10 00 00 00)
|
||||
4 (".strtab"):
|
||||
* Elf32_Word sh_name: 25 (19 00 00 00)
|
||||
* Elf32_Word sh_type: SHT_STRTAB (03 00 00 00)
|
||||
* Elf32_Word sh_flags: 0 (00 00 00 00)
|
||||
* Elf32_Addr sh_addr: 0 (00 00 00 00)
|
||||
* Elf32_Off sh_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_size: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_link: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_info: 0 (00 00 00 00)
|
||||
* Elf32_Word sh_addralign: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_entsize: 0 (00 00 00 00)
|
||||
5 (".rel.text"):
|
||||
* Elf32_Word sh_name: 33 (21 00 00 00)
|
||||
* Elf32_Word sh_type: SHT_REL (09 00 00 00)
|
||||
* Elf32_Word sh_flags: 0 (00 00 00 00)
|
||||
* Elf32_Addr sh_addr: 0 (00 00 00 00)
|
||||
* Elf32_Off sh_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_size: (?? ?? ?? ??)
|
||||
* Elf32_Word sh_link: 3 (03 00 00 00)
|
||||
* Elf32_Word sh_info: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_addralign: 1 (01 00 00 00)
|
||||
* Elf32_Word sh_entsize: 8 (08 00 00 00)
|
||||
|
||||
Symbol format: (4+4+4+1+1+2= 16 bytes)
|
||||
Undefined symbol:
|
||||
* Elf32_Word st_name: 0 (00 00 00 00)
|
||||
* Elf32_Addr st_value: 0 (00 00 00 00)
|
||||
* Elf32_Word st_size: 0 (00 00 00 00)
|
||||
* unsigned char st_info: 0 (00)
|
||||
* unsigned char st_other: 0 (00)
|
||||
* Elf32_Half st_shndx: 0 (00 00)
|
||||
Source file symbol:
|
||||
* Elf32_Word st_name: 1 (01 00 00 00)
|
||||
* Elf32_Addr st_value: 0 (00 00 00 00)
|
||||
* Elf32_Word st_size: 0 (00 00 00 00)
|
||||
* unsigned char st_info: ELF32_ST_INFO(STB_LOCAL, STT_FILE) (04)
|
||||
* unsigned char st_other: 0 (00)
|
||||
* Elf32_Half st_shndx: SHN_ABS (f1 ff)
|
||||
Text section symbol:
|
||||
* Elf32_Word st_name: 0 (00 00 00 00)
|
||||
* Elf32_Addr st_value: 0 (00 00 00 00)
|
||||
* Elf32_Word st_size: 0 (00 00 00 00)
|
||||
* unsigned char st_info: ELF32_ST_INFO(STB_LOCAL, STT_SECTION) (03)
|
||||
* unsigned char st_other: 0 (00)
|
||||
* Elf32_Half st_shndx: 1 (01 00)
|
||||
Undefined symbol:
|
||||
* Elf32_Word st_name: (?? ?? ?? ??)
|
||||
* Elf32_Addr st_value: 0 (00 00 00 00)
|
||||
* Elf32_Word st_size: 0 (00 00 00 00)
|
||||
* unsigned char st_info: ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) (12)
|
||||
* unsigned char st_other: 0 (00)
|
||||
* Elf32_Half st_shndx: 0 (00 00)
|
||||
Defined symbol:
|
||||
* Elf32_Word st_name: (?? ?? ?? ??)
|
||||
* Elf32_Addr st_value: (?? ?? ?? ??)
|
||||
* Elf32_Word st_size: 0 (00 00 00 00)
|
||||
* unsigned char st_info: ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) (12)
|
||||
* unsigned char st_other: 0 (00)
|
||||
* Elf32_Half st_shndx: 1 (01 00)
|
||||
|
||||
Relocation format: (4+4=8)
|
||||
* Elf32_Addr r_offset: (?? ?? ?? ??)
|
||||
* Elf32_Word r_info: ELF32_R_INFO(?, R_386_PC32) (?? ?? ?? ??)
|
602
library/tools/hitutils/hitasm.c
Normal file
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
hitutils - The Sims HIT (dis)assembler and linker
|
||||
hitasm.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#define HITASM_HEADERS
|
||||
#include "hitutils.h"
|
||||
|
||||
static uint8_t ObjectHeader[] = {
|
||||
0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||||
0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x19, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
enum {
|
||||
txt, out, filecount
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t * Data;
|
||||
size_t Position;
|
||||
size_t Size;
|
||||
char * Name;
|
||||
} ByteWriterContext;
|
||||
|
||||
static void bw_expand(ByteWriterContext *bwc){
|
||||
void * ptr;
|
||||
if(bwc->Size > SIZE_MAX/2 || !(ptr = realloc(bwc->Data, bwc->Size<<=1)))
|
||||
Shutdown_M("%sCould not allocate memory for %s section.\n", "hitasm: Error: ", bwc->Name);
|
||||
bwc->Data = ptr;
|
||||
}
|
||||
|
||||
static void bw_write32(ByteWriterContext *bwc, uint32_t value){
|
||||
if(bwc->Size-bwc->Position < 4)
|
||||
bw_expand(bwc);
|
||||
write_uint32(bwc->Data+bwc->Position, value);
|
||||
bwc->Position += 4;
|
||||
}
|
||||
|
||||
static void bw_write8(ByteWriterContext *bwc, uint8_t value){
|
||||
if(bwc->Size-bwc->Position < 1)
|
||||
bw_expand(bwc);
|
||||
bwc->Data[bwc->Position] = value;
|
||||
bwc->Position += 1;
|
||||
}
|
||||
|
||||
static void bw_write_memory(ByteWriterContext *bwc, const uint8_t *ptr, size_t size){
|
||||
while(bwc->Size-bwc->Position < size)
|
||||
bw_expand(bwc);
|
||||
do bwc->Data[bwc->Position++] = *ptr++;
|
||||
while(--size);
|
||||
}
|
||||
|
||||
static void bw_write_string(ByteWriterContext *bwc, const char *string){
|
||||
do bw_write8(bwc, *string);
|
||||
while(*string++);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char * Token;
|
||||
size_t Line, NextLine;
|
||||
size_t Col, NextCol;
|
||||
int GaveLastToken;
|
||||
ByteReaderContext brc;
|
||||
} ParserContext;
|
||||
|
||||
enum {
|
||||
TK_CROSSLINES = 1,
|
||||
CN_LABELONLY = 1
|
||||
};
|
||||
|
||||
enum Sections {
|
||||
Text, SymbolTable, StringTable, RelocationTable, SectionCount
|
||||
};
|
||||
|
||||
static FILE *hFile = NULL;
|
||||
static char *path[filecount] = {NULL};
|
||||
static uint8_t *data[filecount] = {NULL};
|
||||
static ByteWriterContext Section[] = {
|
||||
{0,0,1024,"text"},
|
||||
{0,0,1024,"symtab"},
|
||||
{0,0,1024,"strtab"},
|
||||
{0,0,1024,".rel.text"}
|
||||
};
|
||||
|
||||
static uint8_t * add_symbol(const char * Name){
|
||||
bw_write32(&Section[SymbolTable], Section[StringTable].Position);
|
||||
bw_write32(&Section[SymbolTable], 0);
|
||||
bw_write32(&Section[SymbolTable], 0);
|
||||
bw_write32(&Section[SymbolTable], 18);
|
||||
bw_write_string(&Section[StringTable], Name);
|
||||
return Section[SymbolTable].Data + Section[SymbolTable].Position - 16;
|
||||
}
|
||||
|
||||
static uint8_t * find_symbol_by_name(const char * Name, uint32_t * SymbolIndex){
|
||||
uint32_t p;
|
||||
for(p=48; p<Section[SymbolTable].Position; p+=16){
|
||||
if(!strcmp((char*) Section[StringTable].Data + read_uint32(Section[SymbolTable].Data + p), Name)){
|
||||
if(SymbolIndex) *SymbolIndex = p>>4;
|
||||
return Section[SymbolTable].Data + p;
|
||||
}
|
||||
}
|
||||
|
||||
if(SymbolIndex) *SymbolIndex = p>>4;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline int whitespace(const uint8_t *Data){
|
||||
return (Data[0] == ' ' || Data[0] == '\t' || Data[0] == '\r' || Data[0] == '\n' || Data[0] == '\0');
|
||||
}
|
||||
|
||||
static __inline int comment(const uint8_t *Data){
|
||||
return (Data[0] == ';' || (Data[0] == '#' && whitespace(Data+1)));
|
||||
}
|
||||
|
||||
static int parser_next_token(ParserContext *pc, int CrossLines){
|
||||
if(!pc->brc.Size) return 0;
|
||||
|
||||
if(pc->GaveLastToken){
|
||||
pc->GaveLastToken = 0;
|
||||
/* find the start of the next token */
|
||||
while(1){
|
||||
if(whitespace(pc->brc.Data)){
|
||||
if(pc->brc.Data[0] == '\n'){
|
||||
pc->NextLine++; pc->NextCol = 1;
|
||||
}else if(pc->brc.Data[0] == '\t'){
|
||||
pc->NextCol += 4 - ((pc->NextCol-1)%4);
|
||||
}else{
|
||||
pc->NextCol++;
|
||||
}
|
||||
}else if(comment(pc->brc.Data)){
|
||||
/* skip to the end of the line */
|
||||
pc->NextLine++; pc->NextCol = 1;
|
||||
do {
|
||||
if(!--pc->brc.Size) return 0;
|
||||
pc->brc.Data++;
|
||||
} while(pc->brc.Data[0] != '\n');
|
||||
}else break;
|
||||
|
||||
if(!--pc->brc.Size) return 0;
|
||||
pc->brc.Data++;
|
||||
}
|
||||
}
|
||||
if(!CrossLines && pc->Line != pc->NextLine) return 0;
|
||||
pc->Token = (char*)pc->brc.Data;
|
||||
pc->Line = pc->NextLine;
|
||||
pc->Col = pc->NextCol++;
|
||||
pc->GaveLastToken = 1;
|
||||
|
||||
/* mark the end of this token with a null character */
|
||||
while(1){
|
||||
if(!--pc->brc.Size) return 1;
|
||||
pc->brc.Data++;
|
||||
|
||||
if(whitespace(pc->brc.Data)){
|
||||
if(pc->brc.Data[0] == '\n'){
|
||||
pc->NextLine++; pc->NextCol = 1;
|
||||
}else if(pc->brc.Data[0] == '\t'){
|
||||
pc->NextCol += 4 - ((pc->NextCol-1)%4);
|
||||
}else{
|
||||
pc->NextCol++;
|
||||
}
|
||||
break;
|
||||
}else if(comment(pc->brc.Data)){
|
||||
/* skip to the end of the line */
|
||||
pc->NextLine++; pc->NextCol = 1;
|
||||
do {
|
||||
if(!--pc->brc.Size) return 1;
|
||||
pc->brc.Data++;
|
||||
} while(pc->brc.Data[0] != '\n');
|
||||
break;
|
||||
}else pc->NextCol++;
|
||||
}
|
||||
pc->brc.Size--;
|
||||
pc->brc.Data[0] = '\0';
|
||||
pc->brc.Data++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static __inline void verify_eol(ParserContext *pc){
|
||||
if(parser_next_token(pc, 0))
|
||||
Shutdown_M("%s:%u:%u: error: expected newline before '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
}
|
||||
|
||||
static void verify_name(const ParserContext *pc, const char *thistoken, const char *nexttoken){
|
||||
const char *Name;
|
||||
for(Name = pc->Token; *Name; Name++)
|
||||
if((Name == pc->Token || *Name < '0' || *Name > '9')
|
||||
&& (*Name < 'A' || *Name > 'Z') && (*Name < '_' || *Name > '_') && (*Name < 'a' || *Name > 'z'))
|
||||
Shutdown_M("%s:%u:%u: error: expected %s before '%c'\n",
|
||||
path[txt], pc->Line, pc->Col, (Name == pc->Token) ? thistoken : nexttoken, *Name);
|
||||
}
|
||||
|
||||
static __inline void parser_add_symbol(const ParserContext *pc){
|
||||
uint8_t * Symbol;
|
||||
verify_name(pc, "label or integer constant", "newline");
|
||||
|
||||
/* we're using the ELF st_size field (offset 8) to hold the line number temporarily */
|
||||
Symbol = find_symbol_by_name(pc->Token, NULL);
|
||||
if(Symbol){
|
||||
if(read_uint32(Symbol+4))
|
||||
Shutdown_M("%s:%u:%u: error: label '%s' redefined (previous definition at %s:%u:1)\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token, path[txt], read_uint32(Symbol+8));
|
||||
}else Symbol = add_symbol(pc->Token);
|
||||
|
||||
write_uint32(Symbol+4, Section[Text].Position);
|
||||
write_uint32(Symbol+8, pc->Line);
|
||||
}
|
||||
|
||||
static __inline void parser_add_reference(const ParserContext *pc){
|
||||
uint32_t SymbolIndex;
|
||||
verify_name(pc, "label", "operand or newline");
|
||||
|
||||
if(!find_symbol_by_name(pc->Token, &SymbolIndex))
|
||||
add_symbol(pc->Token);
|
||||
|
||||
bw_write32(&Section[RelocationTable], Section[Text].Position);
|
||||
bw_write32(&Section[RelocationTable], (SymbolIndex<<8)|0x02);
|
||||
}
|
||||
|
||||
static uint32_t read_integer(const ParserContext *pc, uint32_t maxval){
|
||||
unsigned long value;
|
||||
char * endptr;
|
||||
|
||||
if(pc->Token[0] == '-')
|
||||
Shutdown_M("%s:%u:%u: error: integer constant '%s' may not be negative\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
if(pc->Token[0] < '0' || pc->Token[0] > '9')
|
||||
Shutdown_M("%s:%u:%u: error: expected integer constant before '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
if(pc->Token[0] == '0' && (pc->Token[1] == 'x' || pc->Token[1] == '0' || pc->Token[1] == 'o'))
|
||||
Shutdown_M("%s:%u:%u: error: illegal %s prefix '%s%c' on integer constant '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token[1] == 'x' ? "hexadecimal" : "octal",
|
||||
pc->Token[1] != '0' ? "0" : "", pc->Token[1], pc->Token);
|
||||
|
||||
value = strtoul(pc->Token, &endptr, 10);
|
||||
if(*endptr == '.')
|
||||
Shutdown_M("%s:%u:%u: error: illegal floating point constant '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, endptr, pc->Token);
|
||||
if(*endptr != '\0')
|
||||
Shutdown_M("%s:%u:%u: error: illegal suffix '%s' on integer constant '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, endptr, pc->Token);
|
||||
if(value > (unsigned long) maxval || errno == ERANGE)
|
||||
Shutdown_M("%s:%u:%u: error: integer constant '%s' is out of range\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
|
||||
return (uint32_t)value;
|
||||
}
|
||||
|
||||
static uint32_t read_constant(ParserContext *pc, int Type, uint32_t maxval){
|
||||
unsigned i;
|
||||
if(pc->Token[0] == '#') /* note that the tokens "#" and "" will never be returned by the parser */
|
||||
pc->Token++;
|
||||
|
||||
if((pc->Token[0] >= '0' && pc->Token[0] <= '9') || pc->Token[0] == '-' || pc->Token[0] == '.'){
|
||||
if(Type == CN_LABELONLY)
|
||||
Shutdown_M("%s:%u:%u: error: explicit address '%s' is forbidden\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
return read_integer(pc, maxval);
|
||||
}
|
||||
|
||||
verify_name(pc, "constant or label", "operand or newline");
|
||||
for(i=0; i<ConstantCount; i++){
|
||||
if(!strcmp(Constants[i].Name, pc->Token)){
|
||||
if(Constants[i].Value > maxval)
|
||||
Shutdown_M("%s:%u:%u: error: integer constant '%s' (%u) is out of range\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token, Constants[i].Value);
|
||||
return Constants[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
if(maxval != 0xFFFFFFFF)
|
||||
Shutdown_M("%s:%u:%u: error: address referenced by label '%s' is out of range\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
parser_add_reference(pc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline uint8_t read_instruction(const ParserContext *pc, uint32_t *operands){
|
||||
uint8_t i;
|
||||
verify_name(pc, "instruction", "operand or newline");
|
||||
|
||||
for(i=0; i<InstructionCount; i++){
|
||||
if(!strcmp(pc->Token, Instructions[i].Name)){
|
||||
*operands = Instructions[i].Operands;
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline uint8_t read_variable(const ParserContext *pc, const variable_t *Variables, size_t VariableCount){
|
||||
unsigned i;
|
||||
verify_name(pc, "variable", "operand or newline");
|
||||
|
||||
for(i=0; i<VariableCount; i++)
|
||||
if(!strcmp(Variables[i].Name, pc->Token))
|
||||
return Variables[i].Value;
|
||||
|
||||
Shutdown_M("%s:%u:%u: error: unrecognized variable '%s'\n",
|
||||
path[txt], pc->Line, pc->Col, pc->Token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Shutdown(){
|
||||
unsigned i;
|
||||
for(i=0; i<filecount; i++){
|
||||
free(path[i]);
|
||||
free(data[i]);
|
||||
}
|
||||
for(i=0; i<SectionCount; i++)
|
||||
free(Section[i].Data);
|
||||
if(hFile)
|
||||
fclose(hFile);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned i;
|
||||
int SimsVersion = 0;
|
||||
int overwrite = 0;
|
||||
size_t filesize[filecount-1];
|
||||
unsigned slash;
|
||||
const variable_t * Variables;
|
||||
size_t VariableCount;
|
||||
ParserContext pc;
|
||||
int InBinary = 0;
|
||||
uint8_t * SectionHeader;
|
||||
size_t SectionOffset;
|
||||
|
||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: hitasm [-ts1|-tso] [-f] [-o outfile.o] infile.txt\n"
|
||||
"Assemble a HIT source file to an intermediary object file\n"
|
||||
"which can be linked using hitld.\n"
|
||||
"\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"hitutils is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
for(i=1; i<(unsigned)argc-1; i++){
|
||||
if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1;
|
||||
else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO;
|
||||
else if(!strcmp(argv[i], "-f")) overwrite = 1;
|
||||
else if(i != (unsigned)argc-2){
|
||||
if(!strcmp(argv[i], "-o")) path[out] = argv[++i];
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
path[txt] = argv[i];
|
||||
for(i=0; i<filecount; i++)
|
||||
if(path[i])
|
||||
path[i] = strdup(path[i]); /* necessary for free(path[i]) in Shutdown_M */
|
||||
|
||||
if(!SimsVersion)
|
||||
Shutdown_M("%sSims version not specified. (Use -ts1 or -tso.)\n", "hitasm: Error: ");
|
||||
|
||||
if(SimsVersion == VERSION_TS1){
|
||||
Variables = TS1Variables;
|
||||
VariableCount = TS1VariableCount;
|
||||
}else{
|
||||
Variables = TSOVariables;
|
||||
VariableCount = TSOVariableCount;
|
||||
}
|
||||
|
||||
if(path[out] == NULL){
|
||||
int length = strlen(path[txt]);
|
||||
path[out] = malloc(max(length+1, 3));
|
||||
strcpy(path[out], path[txt]);
|
||||
strcpy(path[out] + max(length-4, 0), ".o");
|
||||
}
|
||||
|
||||
/****
|
||||
** Read all of the requested files
|
||||
*/
|
||||
|
||||
for(i=0; i<filecount-1; i++){
|
||||
size_t bytestransferred;
|
||||
|
||||
hFile = fopen(path[i], "rb");
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
filesize[i] = ftell(hFile);
|
||||
if(filesize[i] == 0 || filesize[i] == SIZE_MAX)
|
||||
Shutdown_M("%sFile is invalid: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
data[i] = malloc(filesize[i]+1);
|
||||
if(data[i] == NULL)
|
||||
Shutdown_M("%sCould not allocate memory for file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
bytestransferred = fread(data[i], 1, filesize[i], hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
if(bytestransferred != filesize[i])
|
||||
Shutdown_M("%sCould not read file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
data[i][filesize[i]++] = '\0'; /* add a null character to the end of the file */
|
||||
}
|
||||
|
||||
/****
|
||||
** Open the output file for writing
|
||||
*/
|
||||
|
||||
if(!overwrite){
|
||||
hFile = fopen(path[out], "rb");
|
||||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile); hFile = NULL;
|
||||
fprintf(stderr, "%sFile \"%s\" exists.\nContinue anyway? (y/n) ", "hitasm: ", path[out]);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y')
|
||||
Shutdown_M("\nAborted.\n");
|
||||
}
|
||||
}
|
||||
hFile = fopen(path[out], "wb");
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitasm: Error: ", path[out]);
|
||||
|
||||
/****
|
||||
** Perform the assembly
|
||||
*/
|
||||
|
||||
for(i=0; i<SectionCount; i++){
|
||||
Section[i].Data = malloc(Section[Text].Size);
|
||||
if(!Section[i].Data)
|
||||
Shutdown_M("%sCould not allocate memory for %s section.\n", "hitasm: Error: ", Section[i].Name);
|
||||
}
|
||||
pc.NextLine = 1;
|
||||
pc.NextCol = 1;
|
||||
pc.GaveLastToken = 1;
|
||||
pc.brc.Data = data[txt];
|
||||
pc.brc.Size = filesize[txt];
|
||||
|
||||
bw_write_memory(&Section[SymbolTable], SymbolTableHeader, sizeof(SymbolTableHeader));
|
||||
|
||||
for(i=slash=0; path[txt][i]; i++)
|
||||
if(path[txt][i] == '/' || path[txt][i] == '\\') slash = i+1;
|
||||
bw_write8(&Section[StringTable], '\0');
|
||||
bw_write_string(&Section[StringTable], path[txt] + slash);
|
||||
|
||||
while(parser_next_token(&pc, TK_CROSSLINES)){
|
||||
/* Unimplemented commands */
|
||||
if(!strcmp(pc.Token, "BASEID_TRACKDATA") || !strcmp(pc.Token, "INCLUDE")
|
||||
|| !strcmp(pc.Token, "include") || !strcmp(pc.Token, "INIFILE")
|
||||
|| !strcmp(pc.Token, "LIST") || !strcmp(pc.Token, "SYMBOLFILE")){
|
||||
if(InBinary)
|
||||
Shutdown_M("%s:%u:%u: error: invalid use of '%s' inside BINARY section\n",
|
||||
path[txt], pc.Line, pc.Col, pc.Token);
|
||||
while(parser_next_token(&pc, 0)); /* skip to the end of the line */
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strcmp(pc.Token, "BINARY") && !InBinary){
|
||||
InBinary++;
|
||||
if(!parser_next_token(&pc, TK_CROSSLINES) || strcmp(pc.Token, "["))
|
||||
Shutdown_M("%s:%u:%u: error: expected '[' for beginning of BINARY section before %s%s%s\n",
|
||||
path[txt], pc.Line, pc.Col,
|
||||
pc.Token ? "'" : "", pc.Token ? pc.Token : "end of file", pc.Token ? "'" : "");
|
||||
}
|
||||
|
||||
else if(!strcmp(pc.Token, "]") && InBinary)
|
||||
InBinary--;
|
||||
|
||||
else if(!InBinary)
|
||||
Shutdown_M("%s:%u:%u: error: '%s' is not a valid command\n",
|
||||
path[txt], pc.Line, pc.Col, pc.Token);
|
||||
|
||||
/****
|
||||
** Inside a BINARY section
|
||||
*/
|
||||
|
||||
else if(pc.Col == 1) /* no indent */
|
||||
parser_add_symbol(&pc);
|
||||
|
||||
else{ /* indent */
|
||||
uint8_t opcode;
|
||||
uint32_t operands;
|
||||
|
||||
if((pc.Token[0] >= '0' && pc.Token[0] <= '9') || pc.Token[0] == '-' || pc.Token[0] == '.'
|
||||
|| pc.Token[0] == '#' || !(opcode = read_instruction(&pc, &operands))){
|
||||
/* declare bytes (db and dd pseudo-instructions) */
|
||||
do {
|
||||
if(pc.Token[0] != '#')
|
||||
bw_write8(&Section[Text], read_integer(&pc, 0x000000FF));
|
||||
else
|
||||
bw_write32(&Section[Text], read_constant(&pc, 0, 0xFFFFFFFF));
|
||||
} while(parser_next_token(&pc, 0));
|
||||
continue;
|
||||
}else{
|
||||
const char * InstructionName = pc.Token;
|
||||
bw_write8(&Section[Text], opcode);
|
||||
|
||||
for(i=0; (operands >>= 4) != 0; i++){
|
||||
int type = operands & 15;
|
||||
const char *position[] = {"one","two","three","four"};
|
||||
|
||||
if(!parser_next_token(&pc, 0)){
|
||||
int j;
|
||||
for(j=i+1; (operands >>= 4) != 0; j++);
|
||||
Shutdown_M("%s:%u:%u: error: instruction '%s' wants %s operands but only %s supplied\n",
|
||||
path[txt], pc.Line, pc.Col, pc.Token, InstructionName, position[j], position[i]);
|
||||
}
|
||||
|
||||
if(type == o_byte)
|
||||
bw_write8(&Section[Text], read_constant(&pc, 0, 0x000000FF));
|
||||
else if(type == o_dword)
|
||||
bw_write32(&Section[Text], read_constant(&pc, 0, 0xFFFFFFFF));
|
||||
else if(type == o_address)
|
||||
bw_write32(&Section[Text], read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF));
|
||||
else if(type == o_variable)
|
||||
bw_write8(&Section[Text], read_variable(&pc, Variables, VariableCount));
|
||||
else if(type == o_jump){
|
||||
/* TODO: Change this */
|
||||
bw_write32(&Section[Text], read_constant(&pc, CN_LABELONLY, 0xFFFFFFFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
verify_eol(&pc);
|
||||
}
|
||||
|
||||
if(InBinary)
|
||||
Shutdown_M("%s:%u:%u: error: expected ']' for end of BINARY section before end of file\n",
|
||||
path[txt], pc.Line, pc.Col);
|
||||
|
||||
/****
|
||||
** Prepare and write out the ELF object header and all sections
|
||||
*/
|
||||
|
||||
for(i=48+8; i<Section[SymbolTable].Position; i+=16)
|
||||
write_uint32(Section[SymbolTable].Data + i, 0); /* clear the st_size field we used temporarily */
|
||||
|
||||
if(SimsVersion == VERSION_TSO)
|
||||
ObjectHeader[36]++; /* set the lsb of the processor flags to indicate that this code is for TSO */
|
||||
|
||||
for(i = 0, SectionHeader = ObjectHeader + 120, SectionOffset = 304; i < SectionCount; i++){
|
||||
write_uint32(SectionHeader + 0, SectionOffset);
|
||||
write_uint32(SectionHeader + 4, Section[i].Position);
|
||||
SectionHeader += 40;
|
||||
SectionOffset += Section[i].Position;
|
||||
|
||||
if(i == 0){
|
||||
write_uint32(SectionHeader + 0, SectionOffset);
|
||||
write_uint32(SectionHeader + 4, sizeof(SHStringTable));
|
||||
SectionHeader += 40;
|
||||
SectionOffset += sizeof(SHStringTable);
|
||||
}
|
||||
}
|
||||
|
||||
fwrite(ObjectHeader, 1, sizeof(ObjectHeader), hFile);
|
||||
fwrite(Section[Text].Data, 1, Section[Text].Position, hFile);
|
||||
fwrite(SHStringTable, 1, sizeof(SHStringTable), hFile);
|
||||
for(i=1; i<SectionCount; i++)
|
||||
fwrite(Section[i].Data, 1, Section[i].Position, hFile);
|
||||
|
||||
Shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
638
library/tools/hitutils/hitdump.c
Normal file
|
@ -0,0 +1,638 @@
|
|||
/*
|
||||
hitutils - The Sims HIT (dis)assembler and linker
|
||||
hitdump.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "hitutils.h"
|
||||
|
||||
enum {
|
||||
hsm, hot, evt, hit, out, filecount
|
||||
};
|
||||
|
||||
static __inline const char * find_variable(uint32_t x, const variable_t * Variables, size_t VariableCount){
|
||||
size_t i;
|
||||
for(i=0; i<VariableCount; i++)
|
||||
if(Variables[i].Value == x)
|
||||
return Variables[i].Name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum TokenizeType {
|
||||
TK_STRING,
|
||||
TK_ID
|
||||
};
|
||||
|
||||
static int parser_find(ByteReaderContext *brc, ...){
|
||||
va_list args;
|
||||
va_start(args, brc);
|
||||
|
||||
while(1){
|
||||
uint8_t * Start = brc->Data;
|
||||
const char * Pattern;
|
||||
size_t Length;
|
||||
void * Destination;
|
||||
enum TokenizeType Type;
|
||||
|
||||
Pattern = va_arg(args, const char *);
|
||||
if(Pattern == NULL){
|
||||
va_end(args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(Length = strlen(Pattern); ; brc->Data++, brc->Size--){
|
||||
if(brc->Size < Length){
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
if(!memcmp(brc->Data, Pattern, Length)) break;
|
||||
}
|
||||
*brc->Data = '\0';
|
||||
brc->Data += Length; brc->Size -= Length;
|
||||
|
||||
Destination = va_arg(args, void *);
|
||||
if(Destination == NULL)
|
||||
continue;
|
||||
|
||||
Type = va_arg(args, enum TokenizeType);
|
||||
if(Type == TK_STRING)
|
||||
*((char**)Destination) = (char*)Start;
|
||||
else
|
||||
*((uint32_t*)Destination) = strtoul((char*)Start, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t LogicalAddress;
|
||||
uint32_t TrackID;
|
||||
uint32_t SoundID;
|
||||
char * Name;
|
||||
uint32_t Exported;
|
||||
} address_t;
|
||||
|
||||
typedef struct {
|
||||
size_t SizeAllocated;
|
||||
size_t Count;
|
||||
address_t * Entries;
|
||||
} addresslist_t;
|
||||
|
||||
static address_t * add_address(addresslist_t * List){
|
||||
if(List->Count*sizeof(address_t) == List->SizeAllocated){
|
||||
void * ptr;
|
||||
if(List->SizeAllocated > SIZE_MAX/2 || !(ptr = realloc(List->Entries, List->SizeAllocated<<=1)))
|
||||
Shutdown_M("%sCould not allocate memory for address list.\n", "hitdump: Error: ");
|
||||
List->Entries = ptr;
|
||||
}
|
||||
return memset(List->Entries + List->Count++, 0, sizeof(address_t));
|
||||
}
|
||||
|
||||
static __inline address_t * find_address_by_track_id(addresslist_t * List, uint32_t TrackID){
|
||||
unsigned i;
|
||||
for(i=0; i<List->Count; i++){
|
||||
if(List->Entries[i].TrackID == TrackID)
|
||||
return List->Entries + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline address_t * find_address_by_sound_id(addresslist_t * List, uint32_t SoundID){
|
||||
unsigned i;
|
||||
for(i=0; i<List->Count; i++){
|
||||
if(List->Entries[i].SoundID == SoundID)
|
||||
return List->Entries + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline address_t * find_address_by_logical_address(addresslist_t * List, uint32_t LogicalAddress){
|
||||
unsigned i;
|
||||
for(i=0; i<List->Count; i++){
|
||||
if(List->Entries[i].LogicalAddress == LogicalAddress)
|
||||
return List->Entries + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline address_t * find_address_by_name(addresslist_t * List, const char * Name){
|
||||
unsigned i;
|
||||
for(i=0; i<List->Count; i++){
|
||||
if(List->Entries[i].Name && !strcmp(List->Entries[i].Name, Name))
|
||||
return List->Entries + i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline void read_hit_addresses(uint8_t * Data, size_t Size, addresslist_t * AddressList, uint32_t * SymbolTable){
|
||||
uint8_t * TableData;
|
||||
unsigned i, count = 0;
|
||||
ByteReaderContext brc;
|
||||
brc.Data = Data; brc.Size = Size;
|
||||
|
||||
if(!parser_find(&brc, "ENTP", NULL, NULL) || brc.Size < 4) return;
|
||||
TableData = brc.Data;
|
||||
*SymbolTable = TableData - 4 - Data;
|
||||
|
||||
while(memcmp(Data, "EENT", 4)){
|
||||
if(Size < 12) return;
|
||||
Data+=8; Size-=8;
|
||||
count++;
|
||||
}
|
||||
|
||||
for(i=0; i<count; i++){
|
||||
address_t * Address = add_address(AddressList);
|
||||
Address->Exported = 1;
|
||||
Address->TrackID = read_uint32(TableData); TableData+=4;
|
||||
Address->LogicalAddress = read_uint32(TableData); TableData+=4;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void read_evt_addresses(uint8_t * Data, size_t Size, addresslist_t * AddressList){
|
||||
ByteReaderContext brc;
|
||||
brc.Data = Data; brc.Size = Size;
|
||||
|
||||
while(1){
|
||||
address_t * Address;
|
||||
char *Name;
|
||||
uint32_t TrackID;
|
||||
if(!parser_find(&brc,
|
||||
",", &Name, TK_STRING,
|
||||
",", NULL,
|
||||
",", &TrackID, TK_ID,
|
||||
NULL)) return;
|
||||
|
||||
Address = find_address_by_track_id(AddressList, TrackID);
|
||||
if(!Address){
|
||||
Address = add_address(AddressList);
|
||||
Address->Exported = 1;
|
||||
Address->TrackID = TrackID;
|
||||
}
|
||||
Address->Name = Name;
|
||||
if(!parser_find(&brc, "\n", NULL, NULL)) return;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void read_hsm_addresses(uint8_t * Data, size_t Size, addresslist_t * AddressList){
|
||||
ByteReaderContext brc;
|
||||
brc.Data = Data; brc.Size = Size;
|
||||
|
||||
while(1){
|
||||
address_t * Address;
|
||||
char * Name;
|
||||
uint32_t SoundID, LogicalAddress;
|
||||
if(!parser_find(&brc,
|
||||
"\ntkd_", NULL,
|
||||
" ", &Name, TK_STRING,
|
||||
" ", &SoundID, TK_ID,
|
||||
" ", NULL,
|
||||
" ", &LogicalAddress, TK_ID,
|
||||
NULL)) return;
|
||||
|
||||
Address = find_address_by_logical_address(AddressList, LogicalAddress);
|
||||
if(!Address){
|
||||
Address = find_address_by_name(AddressList, (char*)Name);
|
||||
if(!Address){
|
||||
Address = add_address(AddressList);
|
||||
Address->Name = (char*)Name;
|
||||
}
|
||||
Address->LogicalAddress = LogicalAddress;
|
||||
} else Address->Name = Name;
|
||||
Address->SoundID = SoundID;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void read_hot_trackdata(uint8_t * Data, size_t Size, addresslist_t * AddressList){
|
||||
ByteReaderContext brc;
|
||||
brc.Data = Data; brc.Size = Size;
|
||||
|
||||
if(!parser_find(&brc, "[TrackData]", NULL, NULL)) return;
|
||||
|
||||
while(1){
|
||||
address_t * Address;
|
||||
uint32_t SoundID, LogicalAddress;
|
||||
if(!brc.Size || *brc.Data == '\r' || *brc.Data == '\n' || *brc.Data == '[') return;
|
||||
if(!parser_find(&brc,
|
||||
"=", &SoundID, TK_ID,
|
||||
"\n", &LogicalAddress, TK_ID,
|
||||
NULL)) return;
|
||||
|
||||
Address = find_address_by_logical_address(AddressList, LogicalAddress);
|
||||
if(!Address){
|
||||
Address = find_address_by_sound_id(AddressList, SoundID);
|
||||
if(!Address){
|
||||
Address = add_address(AddressList);
|
||||
Address->SoundID = SoundID;
|
||||
}
|
||||
Address->LogicalAddress = LogicalAddress;
|
||||
} else Address->SoundID = SoundID;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void read_hot_track(uint8_t * Data, size_t Size, addresslist_t * AddressList){
|
||||
ByteReaderContext brc;
|
||||
brc.Data = Data; brc.Size = Size;
|
||||
|
||||
if(!parser_find(&brc, "[Track]", NULL, NULL)) return;
|
||||
|
||||
while(1){
|
||||
address_t * Address;
|
||||
char * Name;
|
||||
uint32_t TrackID;
|
||||
if(!brc.Size || *brc.Data == '\r' || *brc.Data == '\n' || *brc.Data == '[') return;
|
||||
if(!parser_find(&brc,
|
||||
"=", &TrackID, TK_ID,
|
||||
",", NULL,
|
||||
",", &Name, TK_STRING,
|
||||
NULL)) return;
|
||||
|
||||
Address = find_address_by_name(AddressList, (char*)Name);
|
||||
if(!Address){
|
||||
Address = find_address_by_track_id(AddressList, TrackID);
|
||||
if(!Address){
|
||||
Address = add_address(AddressList);
|
||||
Address->TrackID = TrackID;
|
||||
}
|
||||
Address->Name = Name;
|
||||
} else Address->TrackID = TrackID;
|
||||
Address->Exported = 1;
|
||||
|
||||
if(!parser_find(&brc, "\n", NULL, NULL)) return;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void read_hot_addresses(uint8_t * Data, size_t Size, addresslist_t * AddressList){
|
||||
read_hot_trackdata(Data, Size, AddressList);
|
||||
read_hot_track(Data, Size, AddressList);
|
||||
}
|
||||
|
||||
static FILE *hFile = NULL;
|
||||
static char *path[filecount] = {NULL};
|
||||
static uint8_t *data[filecount] = {NULL};
|
||||
static char *basename = NULL;
|
||||
static addresslist_t AddressList = {0};
|
||||
|
||||
static void Shutdown(){
|
||||
unsigned i;
|
||||
for(i=0; i<filecount; i++){
|
||||
free(path[i]);
|
||||
free(data[i]);
|
||||
}
|
||||
free(basename);
|
||||
free(AddressList.Entries);
|
||||
if(hFile)
|
||||
fclose(hFile);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned i, addr;
|
||||
int SimsVersion = 0;
|
||||
int overwrite = 0;
|
||||
int ShowAddresses = 0;
|
||||
int length;
|
||||
size_t filesize[filecount-1];
|
||||
const variable_t * Variables;
|
||||
size_t VariableCount;
|
||||
uint32_t SymbolTable = 0;
|
||||
uint32_t BaseSoundID = 0, BaseSoundIDSet = 0;
|
||||
|
||||
/****
|
||||
** Parse the command-line arguments
|
||||
*/
|
||||
|
||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: hitdump [-ts1|-tso] [-f] [-a] [-o outfile.txt] [-hsm infile.hsm]\n"
|
||||
" [-hot infile.hot] [-evt infile.evt] infile.hit\n"
|
||||
"Disassemble a HIT binary.\n"
|
||||
"\n"
|
||||
"The HSM, HOT, and EVT files are not strictly necessary but\n"
|
||||
"each help in their own way to provide labels for addresses.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
"Use -a to show addresses (verbose).\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"hitutils is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i=1; i<(unsigned)argc-1; i++){
|
||||
if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1;
|
||||
else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO;
|
||||
else if(!strcmp(argv[i], "-f")) overwrite = 1;
|
||||
else if(!strcmp(argv[i], "-a")) ShowAddresses = 1;
|
||||
else if(i != (unsigned)argc-2){
|
||||
if(!strcmp(argv[i], "-o")) path[out] = argv[++i];
|
||||
else if(!strcmp(argv[i], "-hsm")) path[hsm] = argv[++i];
|
||||
else if(!strcmp(argv[i], "-hot")) path[hot] = argv[++i];
|
||||
else if(!strcmp(argv[i], "-evt")) path[evt] = argv[++i];
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
path[hit] = argv[i];
|
||||
for(i=0; i<filecount; i++)
|
||||
if(path[i])
|
||||
path[i] = strdup(path[i]); /* necessary for free(path[i]) in Shutdown_M */
|
||||
|
||||
if(!SimsVersion)
|
||||
Shutdown_M("%sSims version not specified. (Use -ts1 or -tso.)\n", "hitdump: Error: ");
|
||||
|
||||
if(SimsVersion == VERSION_TS1){
|
||||
Variables = TS1Variables;
|
||||
VariableCount = TS1VariableCount;
|
||||
}else{
|
||||
Variables = TSOVariables;
|
||||
VariableCount = TSOVariableCount;
|
||||
}
|
||||
|
||||
length = strlen(path[hit]);
|
||||
if(path[out] == NULL){
|
||||
path[out] = malloc(max(length+1, 5));
|
||||
strcpy(path[out], path[hit]);
|
||||
strcpy(path[out] + max(length-4, 0), ".txt");
|
||||
}
|
||||
length = max(length+1-4, 1);
|
||||
basename = malloc(length);
|
||||
memcpy(basename, path[hit], length-1);
|
||||
basename[length-1] = '\0';
|
||||
|
||||
/****
|
||||
** Read all of the requested files
|
||||
*/
|
||||
|
||||
for(i=0; i<filecount-1; i++){
|
||||
size_t bytestransferred;
|
||||
if(!path[i]) continue;
|
||||
|
||||
hFile = fopen(path[i], "rb");
|
||||
if(hFile == NULL){
|
||||
if(i != hit){
|
||||
fprintf(stderr, "%sCould not open file: %s.\n", "hitdump: Warning: ", path[i]);
|
||||
continue;
|
||||
}else
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitdump: Error: ", path[i]);
|
||||
}
|
||||
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
filesize[i] = ftell(hFile);
|
||||
if(filesize[i] == 0){
|
||||
fclose(hFile); hFile = NULL;
|
||||
if(i != hit){
|
||||
fprintf(stderr, "%sFile is invalid: %s.\n", "hitdump: Warning: ", path[i]);
|
||||
continue;
|
||||
}else
|
||||
Shutdown_M("%sFile is invalid: %s.\n", "hitdump: Error: ", path[i]);
|
||||
}
|
||||
|
||||
data[i] = malloc(filesize[i]);
|
||||
if(data[i] == NULL){
|
||||
fclose(hFile); hFile = NULL;
|
||||
if(i != hit){
|
||||
fprintf(stderr, "%sCould not allocate memory for file: %s.\n", "hitdump: Warning: ", path[i]);
|
||||
continue;
|
||||
}else
|
||||
Shutdown_M("%sCould not allocate memory for file: %s.\n", "hitdump: Error: ", path[i]);
|
||||
}
|
||||
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
bytestransferred = fread(data[i], 1, filesize[i], hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
if(bytestransferred != filesize[i]){
|
||||
free(data[i]); data[i] = NULL;
|
||||
if(i != hit){
|
||||
fprintf(stderr, "%sCould not read file: %s.\n", "hitdump: Warning: ", path[i]);
|
||||
continue;
|
||||
}else
|
||||
Shutdown_M("%sCould not read file: %s.\n", "hitdump: Error: ", path[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
** Open the output file for writing
|
||||
*/
|
||||
|
||||
if(!overwrite){
|
||||
hFile = fopen(path[out], "rb");
|
||||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile); hFile = NULL;
|
||||
fprintf(stderr, "%sFile \"%s\" exists.\nContinue anyway? (y/n) ", "hitdump: ", path[out]);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y')
|
||||
Shutdown_M("\nAborted.\n");
|
||||
}
|
||||
}
|
||||
hFile = fopen(path[out], "wb");
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitdump: Error: ", path[out]);
|
||||
|
||||
/****
|
||||
** Verify the header of the HIT file
|
||||
*/
|
||||
|
||||
if(filesize[hit] < 16 || memcmp(data[hit], HITHeader, 16))
|
||||
Shutdown_M("%sFile is invalid: %s.\n", "hitdump: Error: ", path[hit]);
|
||||
|
||||
/****
|
||||
** Build up the address list
|
||||
*/
|
||||
|
||||
AddressList.SizeAllocated = 32 * sizeof(address_t);
|
||||
AddressList.Count = 0;
|
||||
AddressList.Entries = malloc(32 * sizeof(address_t));
|
||||
|
||||
read_hit_addresses(data[hit], filesize[hit], &AddressList, &SymbolTable);
|
||||
if(data[evt]) read_evt_addresses(data[evt], filesize[evt], &AddressList);
|
||||
if(data[hsm]) read_hsm_addresses(data[hsm], filesize[hsm], &AddressList);
|
||||
if(data[hot]) read_hot_addresses(data[hot], filesize[hot], &AddressList);
|
||||
/* scan_branch_destinations(data[hit], filesize[hit], &AddressList); */
|
||||
|
||||
for(i=0; i<AddressList.Count; i++){
|
||||
if(AddressList.Entries[i].SoundID != 0 && (!BaseSoundIDSet || AddressList.Entries[i].SoundID < BaseSoundID)){
|
||||
BaseSoundID = AddressList.Entries[i].SoundID;
|
||||
BaseSoundIDSet = 1;
|
||||
}
|
||||
|
||||
if(ShowAddresses){
|
||||
printf("Address %u:\n Exported: %u\n TrackID: %u\n SoundID: %u\n Name: %s\n LogicalAddress: %u\n", i,
|
||||
AddressList.Entries[i].Exported,
|
||||
AddressList.Entries[i].TrackID,
|
||||
AddressList.Entries[i].SoundID,
|
||||
AddressList.Entries[i].Name ? AddressList.Entries[i].Name : "",
|
||||
AddressList.Entries[i].LogicalAddress
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/****
|
||||
** Perform the disassembly
|
||||
*/
|
||||
|
||||
fprintf(hFile, "BASEID_TRACKDATA %u\r\n"
|
||||
"\r\n"
|
||||
";\r\n"
|
||||
"; generated by hitdump.\r\n"
|
||||
";\r\n"
|
||||
"\r\n"
|
||||
"; useful symbols:\r\n"
|
||||
"; kSndobPlay = 1\r\n"
|
||||
"; tkd_Generic 1\r\n"
|
||||
"; tkd_GenericLooped 2\r\n"
|
||||
"; tkd_GenericHitList 3\r\n"
|
||||
"\r\n"
|
||||
"INCLUDE defaultsyms.txt\r\n"
|
||||
"INCLUDE SimsVariables.txt\r\n"
|
||||
"\r\n"
|
||||
"LIST [Options] Version=1\r\n"
|
||||
"LIST [Options] LoadPriority=2\r\n"
|
||||
"\r\n"
|
||||
";LIST [EventMappingEquate] kSndobPlay=1\r\n"
|
||||
"; --- end of standard intro text ---\r\n"
|
||||
"\r\n"
|
||||
"SYMBOLFILE %s%s\r\n"
|
||||
"INIFILE %s.ini", BaseSoundID, path[hsm] ? path[hsm] : basename, path[hsm] ? "" : ".hsm", basename);
|
||||
|
||||
fprintf(hFile, "\r\n\r\nBINARY\r\n[");
|
||||
|
||||
for(addr=16; addr<filesize[hit];){
|
||||
unsigned i;
|
||||
uint8_t opcode;
|
||||
const instruction_t * instruction;
|
||||
uint32_t operands;
|
||||
const address_t * Address;
|
||||
int HadSymbolTable = 0;
|
||||
|
||||
if(SymbolTable && addr == SymbolTable){
|
||||
if(addr != 16)
|
||||
fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n[");
|
||||
fprintf(hFile, "\r\n"
|
||||
"\t69\r\n"
|
||||
"\t78\r\n"
|
||||
"\t84\r\n"
|
||||
"\t80\r\n");
|
||||
|
||||
for(addr+=4; memcmp(data[hit]+addr, "EENT", 4); addr+=8){
|
||||
uint32_t TrackID = read_uint32(data[hit]+addr), LogicalAddress = read_uint32(data[hit]+addr+4);
|
||||
|
||||
Address = find_address_by_logical_address(&AddressList, LogicalAddress);
|
||||
fprintf(hFile, "\r\n\t#%u\t\t#", TrackID);
|
||||
if(Address && Address->Name) fprintf(hFile, "%s", Address->Name);
|
||||
else fprintf(hFile, "%u", LogicalAddress);
|
||||
}
|
||||
|
||||
if(addr-4 != SymbolTable)
|
||||
fprintf(hFile, "\r\n");
|
||||
fprintf(hFile, "\r\n"
|
||||
"\t69\r\n"
|
||||
"\t69\r\n"
|
||||
"\t78\r\n"
|
||||
"\t84");
|
||||
|
||||
if(addr+4 == filesize[hit])
|
||||
break;
|
||||
fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n[");
|
||||
|
||||
addr += 4;
|
||||
SymbolTable = 0;
|
||||
HadSymbolTable++;
|
||||
}
|
||||
|
||||
Address = find_address_by_logical_address(&AddressList, addr);
|
||||
if(Address){
|
||||
if(!HadSymbolTable && addr != 16 && Address->Exported)
|
||||
fprintf(hFile, "\r\n]\r\n\r\nBINARY\r\n[");
|
||||
if(Address->Name)
|
||||
fprintf(hFile, "\r\n%s", Address->Name);
|
||||
}
|
||||
|
||||
opcode = data[hit][addr];
|
||||
if(opcode == 0 || opcode > InstructionCount)
|
||||
Shutdown_M("%sIllegal opcode 0x%02X at address 0x%08X.\n", "hitdump: Error: ", opcode, addr);
|
||||
|
||||
instruction = Instructions + opcode - 1;
|
||||
operands = instruction->Operands;
|
||||
if(operands == UNIMPLEMENTED)
|
||||
Shutdown_M("%sUnimplemented instruction '%s' at address 0x%08X.\n", "hitdump: Error: ", instruction->Name, addr);
|
||||
|
||||
addr++;
|
||||
|
||||
if(filesize[hit] - addr < (operands & 15))
|
||||
Shutdown_M("%sInsufficient operand bytes for '%s' instruction at address 0x%08X (%u of %u supplied).\n",
|
||||
"hitdump: Error: ", instruction->Name, addr, filesize[hit] - addr, instruction->Operands);
|
||||
|
||||
fprintf(hFile, "\r\n\t\t%s", instruction->Name);
|
||||
for(i=0; (operands >>= 4) != 0; i++){
|
||||
int type = operands & 15;
|
||||
const char *position[] = {"first","second","third","fourth"};
|
||||
if(type == o_byte){
|
||||
fprintf(hFile, " #%u", data[hit][addr]);
|
||||
addr += 1;
|
||||
}else if(type == o_dword){
|
||||
fprintf(hFile, " #%u", read_uint32(data[hit]+addr));
|
||||
addr += 4;
|
||||
}else if(type == o_address){
|
||||
int LogicalAddress = read_uint32(data[hit]+addr);
|
||||
|
||||
Address = find_address_by_logical_address(&AddressList, LogicalAddress);
|
||||
if(Address && Address->Name) fprintf(hFile, " #%s", Address->Name);
|
||||
else fprintf(hFile, " #%u", LogicalAddress);
|
||||
addr += 4;
|
||||
}else if(type == o_variable){
|
||||
unsigned x = data[hit][addr];
|
||||
const char * Variable = find_variable(x, Variables, VariableCount);
|
||||
if(Variable == NULL)
|
||||
Shutdown_M("%sInvalid %s operand 0x%02X for '%s' instruction at address 0x%08X (expected variable).\n",
|
||||
"hitdump: Error: ", position[i], x, instruction->Name, addr);
|
||||
fprintf(hFile, " %s", Variable);
|
||||
addr += 1;
|
||||
}else if(type == o_jump){
|
||||
unsigned x = 0;
|
||||
|
||||
if(filesize[hit]-addr >= 4)
|
||||
x = read_uint32(data[hit]+addr);
|
||||
else if(data[hit][addr] != 0x05 && data[hit][addr] != 0x06)
|
||||
Shutdown_M("%sInsufficient operand bytes for '%s' instruction at address 0x%08X (%u of %u supplied).\n",
|
||||
"hitdump: Error: ", instruction->Name, addr, filesize[hit] - addr, 4);
|
||||
|
||||
if(x >= 16 && x < filesize[hit]){
|
||||
Address = find_address_by_logical_address(&AddressList, x);
|
||||
if(Address && Address->Name) fprintf(hFile, " #%s", Address->Name);
|
||||
else fprintf(hFile, " #%u", x);
|
||||
addr += 4;
|
||||
}else{
|
||||
const char * Variable;
|
||||
x = data[hit][addr];
|
||||
Variable = find_variable(x, Variables, VariableCount);
|
||||
if(Variable == NULL)
|
||||
Shutdown_M("%sInvalid %s operand 0x%02X for '%s' instruction at address 0x%08X (expected variable).\n",
|
||||
"hitdump: Error: ", position[i], x, instruction->Name, addr);
|
||||
fprintf(hFile, " %s", Variable);
|
||||
addr += (data[hit][addr] != 0x05 && data[hit][addr] != 0x06) ? 4 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(hFile, "\r\n]\r\n\r\n");
|
||||
|
||||
Shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
174
library/tools/hitutils/hitld.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
hitutils - The Sims HIT (dis)assembler and linker
|
||||
hitld.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "hitutils.h"
|
||||
|
||||
static const uint8_t ObjectHeader[] = {0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01};
|
||||
static const uint8_t ArchiveHeader[] = {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'};
|
||||
|
||||
enum {
|
||||
hsm, hot, out, filecount
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *path;
|
||||
uint8_t *data;
|
||||
} object_t;
|
||||
|
||||
typedef struct {
|
||||
size_t SizeAllocated;
|
||||
size_t Count;
|
||||
object_t * Entries;
|
||||
} objectlist_t;
|
||||
|
||||
static object_t * add_object(objectlist_t * List){
|
||||
if(List->Count*sizeof(object_t) == List->SizeAllocated){
|
||||
void * ptr;
|
||||
if(List->SizeAllocated > SIZE_MAX/2 || !(ptr = realloc(List->Entries, List->SizeAllocated<<=1)))
|
||||
Shutdown_M("%sCould not allocate memory for object list.\n", "hitld: Error: ");
|
||||
List->Entries = ptr;
|
||||
}
|
||||
return memset(List->Entries + List->Count++, 0, sizeof(object_t));
|
||||
}
|
||||
|
||||
static FILE *hFile = NULL;
|
||||
static char *path[filecount] = {NULL};
|
||||
static uint8_t *data[filecount] = {NULL};
|
||||
static objectlist_t ObjectList = {0};
|
||||
|
||||
static void Shutdown(){
|
||||
unsigned i;
|
||||
for(i=0; i<filecount; i++){
|
||||
free(path[i]);
|
||||
free(data[i]);
|
||||
}
|
||||
for(i=0; i<ObjectList.Count; i++){
|
||||
free(ObjectList.Entries[i].path);
|
||||
free(ObjectList.Entries[i].data);
|
||||
}
|
||||
free(ObjectList.Entries);
|
||||
if(hFile)
|
||||
fclose(hFile);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned i;
|
||||
unsigned ObjectArg;
|
||||
int SimsVersion = 0;
|
||||
int overwrite = 0;
|
||||
size_t filesize[filecount-1];
|
||||
|
||||
if(argc < 3){
|
||||
printf("Usage: hitld [-ts1|-tso] [-f] [-o outfile.hit] [-hsm infile.hsm]\n"
|
||||
" [-hot infile.hot] INFILES\n"
|
||||
"Link object files produced by hitasm into a HIT binary, and\n"
|
||||
"relink the game's HSM and HOT files.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"hitutils is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i=1; i<(unsigned)argc-1; i++){
|
||||
if(!strcmp(argv[i], "-ts1")) SimsVersion = VERSION_TS1;
|
||||
else if(!strcmp(argv[i], "-tso")) SimsVersion = VERSION_TSO;
|
||||
else if(!strcmp(argv[i], "-f")) overwrite = 1;
|
||||
else if(i != (unsigned)argc-2){
|
||||
if(!strcmp(argv[i], "-o")) path[out] = argv[++i];
|
||||
else if(!strcmp(argv[i], "-hsm")) path[hsm] = argv[++i];
|
||||
else if(!strcmp(argv[i], "-hot")) path[hot] = argv[++i];
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
ObjectArg = i;
|
||||
for(i=0; i<filecount; i++)
|
||||
if(path[i])
|
||||
path[i] = strdup(path[i]); /* necessary for free(path[i]) in Shutdown_M */
|
||||
|
||||
if(!SimsVersion)
|
||||
Shutdown_M("%sSims version not specified. (Use -ts1 or -tso.)\n", "hitasm: Error: ");
|
||||
|
||||
if(path[out] == NULL){
|
||||
int length = strlen(argv[ObjectArg]);
|
||||
path[out] = malloc(max(length+1+2, 5));
|
||||
strcpy(path[out], argv[ObjectArg]);
|
||||
strcpy(path[out] + max(length-2, 0), ".hit");
|
||||
}
|
||||
|
||||
/****
|
||||
** Read all of the requested files
|
||||
*/
|
||||
|
||||
for(i=0; i<filecount-1; i++){
|
||||
size_t bytestransferred;
|
||||
if(!path[i]) continue;
|
||||
|
||||
hFile = fopen(path[i], "rb");
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
filesize[i] = ftell(hFile);
|
||||
if(filesize[i] == 0)
|
||||
Shutdown_M("%sFile is invalid: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
data[i] = malloc(filesize[i]);
|
||||
if(data[i] == NULL)
|
||||
Shutdown_M("%sCould not allocate memory for file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
bytestransferred = fread(data[i], 1, filesize[i], hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
if(bytestransferred != filesize[i])
|
||||
Shutdown_M("%sCould not read file: %s.\n", "hitasm: Error: ", path[i]);
|
||||
}
|
||||
|
||||
/****
|
||||
** Open the output file for writing
|
||||
*/
|
||||
|
||||
if(!overwrite){
|
||||
hFile = fopen(path[out], "rb");
|
||||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile); hFile = NULL;
|
||||
fprintf(stderr, "%sFile \"%s\" exists.\nContinue anyway? (y/n) ", "hitdump: ", path[out]);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y')
|
||||
Shutdown_M("\nAborted.\n");
|
||||
}
|
||||
}
|
||||
hFile = fopen(path[out], "wb");
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("%sCould not open file: %s.\n", "hitdump: Error: ", path[out]);
|
||||
|
||||
fwrite(HITHeader, 1, sizeof(HITHeader), hFile);
|
||||
|
||||
Shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
452
library/tools/hitutils/hitutils.h
Normal file
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
hitutils - The Sims HIT (dis)assembler and linker
|
||||
hitutils.h - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef min
|
||||
#define min(x,y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef max
|
||||
#define max(x,y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef read_int32
|
||||
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
|
||||
#ifndef write_int32
|
||||
#define write_uint32(dest, src) do {\
|
||||
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||
} while(0)
|
||||
#define write_uint16(dest, src) do {\
|
||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
extern char *strdup (const char *__s);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
static void Shutdown_M(const char * Message, ...){
|
||||
va_list args;
|
||||
va_start(args, Message);
|
||||
vfprintf(stderr, Message, args);
|
||||
va_end(args);
|
||||
|
||||
Shutdown();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
enum {
|
||||
VERSION_TS1 = 1, VERSION_TSO
|
||||
};
|
||||
|
||||
#define OPERAND_BYTES(x) (x)
|
||||
#define OPERAND(x, y) ((y)<<((x)*4+4))
|
||||
#define UNIMPLEMENTED ((uint32_t)~0)
|
||||
|
||||
enum operand_t {
|
||||
o_byte = 1,
|
||||
o_dword,
|
||||
o_address,
|
||||
o_variable,
|
||||
o_jump
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char * Name;
|
||||
uint32_t Operands;
|
||||
} instruction_t;
|
||||
|
||||
typedef struct {
|
||||
const char * Name;
|
||||
uint32_t Value;
|
||||
} variable_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t * Data;
|
||||
size_t Size;
|
||||
} ByteReaderContext;
|
||||
|
||||
static const uint8_t HITHeader[] = {'H','I','T','!',0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,'T','R','A','X'};
|
||||
|
||||
#define InstructionCount 96
|
||||
static const instruction_t Instructions[] = {
|
||||
{"note", UNIMPLEMENTED},
|
||||
{"note_on", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"note_off", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"loadb", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_byte)},
|
||||
{"loadl", OPERAND_BYTES(5) | OPERAND(0, o_variable) | OPERAND(1, o_dword)},
|
||||
{"set", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"call", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"return", OPERAND_BYTES(0)},
|
||||
{"wait", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"callentrypoint", UNIMPLEMENTED},
|
||||
{"wait_samp", OPERAND_BYTES(0)},
|
||||
{"end", OPERAND_BYTES(0)},
|
||||
{"jump", OPERAND_BYTES(1) | OPERAND(0, o_jump)},
|
||||
{"test", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"nop", OPERAND_BYTES(0)},
|
||||
{"add", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"sub", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"div", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"mul", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"cmp", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"less", UNIMPLEMENTED},
|
||||
{"greater", UNIMPLEMENTED},
|
||||
{"not", UNIMPLEMENTED},
|
||||
{"rand", OPERAND_BYTES(3) | OPERAND(0, o_variable) | OPERAND(1, o_variable) | OPERAND(2, o_variable)},
|
||||
{"abs", UNIMPLEMENTED},
|
||||
{"limit", UNIMPLEMENTED},
|
||||
{"error", UNIMPLEMENTED},
|
||||
{"assert", UNIMPLEMENTED},
|
||||
{"add_to_group", UNIMPLEMENTED},
|
||||
{"remove_from_group", UNIMPLEMENTED},
|
||||
{"get_var", UNIMPLEMENTED},
|
||||
{"loop", OPERAND_BYTES(0)},
|
||||
{"set_loop", OPERAND_BYTES(0)},
|
||||
{"callback", UNIMPLEMENTED},
|
||||
{"smart_add", UNIMPLEMENTED},
|
||||
{"smart_remove", UNIMPLEMENTED},
|
||||
{"smart_removeall", UNIMPLEMENTED},
|
||||
{"smart_setcrit", UNIMPLEMENTED},
|
||||
{"smart_choose", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"and", UNIMPLEMENTED},
|
||||
{"nand", UNIMPLEMENTED},
|
||||
{"or", UNIMPLEMENTED},
|
||||
{"nor", UNIMPLEMENTED},
|
||||
{"xor", UNIMPLEMENTED},
|
||||
{"max", OPERAND_BYTES(5) | OPERAND(0, o_variable) | OPERAND(1, o_dword)},
|
||||
{"min", OPERAND_BYTES(5) | OPERAND(0, o_variable) | OPERAND(1, o_dword)},
|
||||
{"inc", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"dec", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"printreg", UNIMPLEMENTED},
|
||||
{"play_trk", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"kill_trk", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"push", UNIMPLEMENTED},
|
||||
{"push_mask", UNIMPLEMENTED},
|
||||
{"push_vars", UNIMPLEMENTED},
|
||||
{"call_mask", UNIMPLEMENTED},
|
||||
{"call_push", UNIMPLEMENTED},
|
||||
{"pop", UNIMPLEMENTED},
|
||||
{"test1", OPERAND_BYTES(0)},
|
||||
{"test2", OPERAND_BYTES(0)},
|
||||
{"test3", OPERAND_BYTES(0)},
|
||||
{"test4", OPERAND_BYTES(0)},
|
||||
{"ifeq", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"ifne", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"ifgt", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"iflt", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"ifge", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"ifle", OPERAND_BYTES(4) | OPERAND(0, o_address)},
|
||||
{"smart_setlist", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"seqgroup_kill", OPERAND_BYTES(1) | OPERAND(0, o_byte)},
|
||||
{"seqgroup_wait", UNIMPLEMENTED},
|
||||
{"seqgroup_return", OPERAND_BYTES(1) | OPERAND(0, o_byte)},
|
||||
{"getsrcdatafield", OPERAND_BYTES(3) | OPERAND(0, o_variable) | OPERAND(1, o_variable) | OPERAND(2, o_variable)},
|
||||
{"seqgroup_trkid", OPERAND_BYTES(2) | OPERAND(0, o_byte) | OPERAND(1, o_byte)},
|
||||
{"setll", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"setlt", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"settl", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waiteq", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waitne", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waitgt", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waitlt", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waitge", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"waitle", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"duck", OPERAND_BYTES(0)},
|
||||
{"unduck", OPERAND_BYTES(0)},
|
||||
{"testx", UNIMPLEMENTED},
|
||||
{"setlg", OPERAND_BYTES(5) | OPERAND(0, o_variable) | OPERAND(1, o_dword)},
|
||||
{"setgl", OPERAND_BYTES(5) | OPERAND(0, o_variable) | OPERAND(1, o_dword)},
|
||||
{"throw", UNIMPLEMENTED},
|
||||
{"setsrcdatafield", OPERAND_BYTES(3) | OPERAND(0, o_variable) | OPERAND(1, o_variable) | OPERAND(2, o_variable)},
|
||||
{"stop_trk", OPERAND_BYTES(1) | OPERAND(0, o_variable)},
|
||||
{"setchanreg", UNIMPLEMENTED},
|
||||
{"play_note", UNIMPLEMENTED},
|
||||
{"stop_note", UNIMPLEMENTED},
|
||||
{"kill_note", UNIMPLEMENTED},
|
||||
{"smart_index", OPERAND_BYTES(2) | OPERAND(0, o_variable) | OPERAND(1, o_variable)},
|
||||
{"note_on_loop", OPERAND_BYTES(1) | OPERAND(0, o_variable)}
|
||||
};
|
||||
|
||||
#define TSOVariableCount 82
|
||||
static const variable_t TSOVariables[] = {
|
||||
{"arg0", 0x00},
|
||||
{"arg1", 0x01},
|
||||
{"arg2", 0x02},
|
||||
{"arg3", 0x03},
|
||||
{"arg4", 0x04},
|
||||
{"v1", 0x05},
|
||||
{"v2", 0x06},
|
||||
{"v3", 0x07},
|
||||
{"v4", 0x08},
|
||||
{"v5", 0x09},
|
||||
{"v6", 0x0A},
|
||||
{"v7", 0x0B},
|
||||
{"v8", 0x0C},
|
||||
{"h1", 0x0D},
|
||||
{"h2", 0x0E},
|
||||
{"h3", 0x0F},
|
||||
{"argstype", 0x10},
|
||||
{"trackdatasource", 0x11},
|
||||
{"patch", 0x12},
|
||||
{"priority", 0x13},
|
||||
{"vol", 0x14},
|
||||
{"extvol", 0x15},
|
||||
{"pan", 0x16},
|
||||
{"pitch", 0x17},
|
||||
{"paused", 0x18},
|
||||
{"fxtype", 0x19},
|
||||
{"fxlevel", 0x1a},
|
||||
{"duckpri", 0x1b},
|
||||
{"Is3d", 0x1c},
|
||||
{"IsHeadRelative", 0x1d},
|
||||
{"MinDistance", 0x1e},
|
||||
{"MaxDistance", 0x1f},
|
||||
{"X", 0x20},
|
||||
{"Y", 0x21},
|
||||
{"Z", 0x22},
|
||||
{"attack", 0x23},
|
||||
{"decay", 0x24},
|
||||
{"IsStreamed", 0x25},
|
||||
{"bufsizemult", 0x26},
|
||||
{"fade_dest", 0x27},
|
||||
{"fade_var", 0x28},
|
||||
{"fade_speed", 0x29},
|
||||
{"fade_on", 0x2a},
|
||||
{"Preload", 0x2b},
|
||||
{"isplaying", 0x2c},
|
||||
{"whattodowithupdate", 0x2d},
|
||||
{"tempo", 0x2e},
|
||||
{"target", 0x2f},
|
||||
{"ctrlgroup", 0x30},
|
||||
{"interrupt", 0x31},
|
||||
{"ispositioned", 0x32},
|
||||
{"AppObjectId", 0x34},
|
||||
{"callbackarg", 0x35},
|
||||
{"pitchrandmin", 0x36},
|
||||
{"pitchrandmax", 0x37},
|
||||
{"spl", 0x38},
|
||||
{"sem", 0x39},
|
||||
{"starttrackid", 0x3a},
|
||||
{"endtrackid", 0x3b},
|
||||
{"startdelay", 0x3c},
|
||||
{"fadeinspeed", 0x3d},
|
||||
{"fadeoutspeed", 0x3e},
|
||||
{"hitlist", 0x3f},
|
||||
{"SimSpeed", 0x64},
|
||||
{"test_g1", 0x65},
|
||||
{"test_g2", 0x66},
|
||||
{"test_g3", 0x67},
|
||||
{"test_g4", 0x68},
|
||||
{"test_g5", 0x69},
|
||||
{"test_g6", 0x6a},
|
||||
{"test_g7", 0x6b},
|
||||
{"test_g8", 0x6c},
|
||||
{"test_g9", 0x6d},
|
||||
{"main_songnum", 0x6e},
|
||||
{"main_musichitlistid", 0x6f},
|
||||
{"campfire_nexttrack", 0x70},
|
||||
{"campfire_busy", 0x71},
|
||||
{"main_duckpri", 0x7b},
|
||||
{"main_vol", 0x7c},
|
||||
{"main_fxtype", 0x7d},
|
||||
{"main_fxlevel", 0x7e},
|
||||
{"main_pause", 0x7f},
|
||||
};
|
||||
|
||||
#define TS1VariableCount 87
|
||||
static const variable_t TS1Variables[] = {
|
||||
{"arg0", 0x00},
|
||||
{"arg1", 0x01},
|
||||
{"arg2", 0x02},
|
||||
{"arg3", 0x03},
|
||||
{"arg4", 0x04},
|
||||
{"v1", 0x05},
|
||||
{"v2", 0x06},
|
||||
{"v3", 0x07},
|
||||
{"v4", 0x08},
|
||||
{"v5", 0x09},
|
||||
{"v6", 0x0a},
|
||||
{"v7", 0x0b},
|
||||
{"v8", 0x0c},
|
||||
{"h1", 0x0d},
|
||||
{"h2", 0x0e},
|
||||
{"h3", 0x0f},
|
||||
{"priority", 0x11},
|
||||
{"vol", 0x12},
|
||||
{"extvol", 0x13},
|
||||
{"pan", 0x14},
|
||||
{"pitch", 0x15},
|
||||
{"paused", 0x16},
|
||||
{"fxtype", 0x17},
|
||||
{"fxlevel", 0x18},
|
||||
{"duckpri", 0x19},
|
||||
{"Is3d", 0x1a},
|
||||
{"IsHeadRelative", 0x1b},
|
||||
{"MinDistance", 0x1c},
|
||||
{"MaxDistance", 0x1d},
|
||||
{"X", 0x1e},
|
||||
{"Y", 0x1f},
|
||||
{"Z", 0x20},
|
||||
{"filter_type", 0x21},
|
||||
{"filter_cutoff", 0x22},
|
||||
{"filter_level", 0x23},
|
||||
{"attack", 0x24},
|
||||
{"decay", 0x25},
|
||||
{"IsStreamed", 0x26},
|
||||
{"BufSizeMult", 0x27},
|
||||
{"fade_dest", 0x28},
|
||||
{"fade_var", 0x29},
|
||||
{"fade_speed", 0x2a},
|
||||
{"Preload", 0x2b},
|
||||
{"IsLooped", 0x2c},
|
||||
{"fade_on", 0x2d},
|
||||
{"isplaying", 0x2e},
|
||||
{"source", 0x2f},
|
||||
{"patch", 0x32},
|
||||
{"WhatToDoWithUpdate", 0x33},
|
||||
{"tempo", 0x34},
|
||||
{"target", 0x35},
|
||||
{"mutegroup", 0x36},
|
||||
{"interrupt", 0x37},
|
||||
{"IsPositioned", 0x38},
|
||||
{"Spl", 0x39},
|
||||
{"MultipleInstances", 0x3a},
|
||||
{"AssociatedTrack1", 0x3b},
|
||||
{"AssociatedTrack2", 0x3c},
|
||||
{"AssociatedTrack3", 0x3d},
|
||||
{"AssociatedTrack4", 0x3e},
|
||||
{"AssociatedTrack5", 0x3f},
|
||||
{"AssociatedTrack6", 0x40},
|
||||
{"AssociatedTrack7", 0x41},
|
||||
{"AssociatedTrack8", 0x42},
|
||||
{"SimSpeed", 0x64},
|
||||
{"test_g1", 0x65},
|
||||
{"test_g2", 0x66},
|
||||
{"test_g3", 0x67},
|
||||
{"test_g4", 0x68},
|
||||
{"test_g5", 0x69},
|
||||
{"test_g6", 0x6a},
|
||||
{"test_g7", 0x6b},
|
||||
{"test_g8", 0x6c},
|
||||
{"test_g9", 0x6d},
|
||||
{"main_songnum", 0x6e},
|
||||
{"main_musichitlistid", 0x6f},
|
||||
{"campfire_nexttrack", 0x70},
|
||||
{"campfire_busy", 0x71},
|
||||
{"main_duckpri", 0x7b},
|
||||
{"main_vol", 0x7c},
|
||||
{"main_fxtype", 0x7d},
|
||||
{"main_fxlevel", 0x7e},
|
||||
{"main_pause", 0x7f},
|
||||
};
|
||||
|
||||
#define ConstantCount 72
|
||||
static const variable_t Constants[] = {
|
||||
{"duckpri_always", 0x0},
|
||||
{"duckpri_low", 0xa},
|
||||
{"duckpri_normal", 0x14},
|
||||
{"duckpri_high", 0x1e},
|
||||
{"duckpri_higher", 0x28},
|
||||
{"duckpri_evenhigher", 0x32},
|
||||
{"duckpri_never", 0x64},
|
||||
{"spl_infinite", 0x0},
|
||||
{"spl_loud", 0xa},
|
||||
{"spl_normal", 0x14},
|
||||
{"spl_quiet", 0x64},
|
||||
{"Instance", 0x0},
|
||||
{"Gender", 0x1},
|
||||
{"GroupMusic", 0x1},
|
||||
{"GroupDialogMain", 0x2},
|
||||
{"GroupDialogOverlay", 0x3},
|
||||
{"PchDishwasherClose", 0x32},
|
||||
{"PchDishwasherLoad", 0x33},
|
||||
{"PchDishwasherLoad2", 0x34},
|
||||
{"PchDishwasherOpen", 0x35},
|
||||
{"PchDishwasherTurnDial", 0x39},
|
||||
{"PchDishwasherTurnDial2", 0x3a},
|
||||
{"TrkRadioStationCountry", 0x104},
|
||||
{"TrkRadioStationBossaNova", 0x10e},
|
||||
{"TrkRadioStationClassical", 0x10d},
|
||||
{"TrkRadioStationRock", 0x118},
|
||||
{"kSndobPlay", 1},
|
||||
{"kSndobStop", 2},
|
||||
{"kSndobKill", 3},
|
||||
{"kSndobUpdate", 4},
|
||||
{"kSndobSetVolume", 5},
|
||||
{"kSndobSetPitch", 6},
|
||||
{"kSndobSetPan", 7},
|
||||
{"kSndobSetPosition", 8},
|
||||
{"kSndobSetFxType", 9},
|
||||
{"kSndobSetFxLevel", 10},
|
||||
{"kSndobPause", 11},
|
||||
{"kSndobUnpause", 12},
|
||||
{"kSndobLoad", 13},
|
||||
{"kSndobUnload", 14},
|
||||
{"kSndobCache", 15},
|
||||
{"kSndobUncache", 16},
|
||||
{"kSndobCancelNote", 19},
|
||||
{"kPlayPiano", 43},
|
||||
{"kSetMusicMode", 36},
|
||||
{"kLive", 0},
|
||||
{"kBuy", 1},
|
||||
{"kBuild", 2},
|
||||
{"kHood", 3},
|
||||
{"kFrontEnd", 4},
|
||||
{"kGroupSfx", 1},
|
||||
{"kGroupMusic", 2},
|
||||
{"kGroupVox", 3},
|
||||
{"kAction", 1000},
|
||||
{"kComedy", 1001},
|
||||
{"kRomance", 1002},
|
||||
{"kNews", 1003},
|
||||
{"kCountry", 1004},
|
||||
{"kRock", 1005},
|
||||
{"kJazz", 1006},
|
||||
{"kClassical", 1007},
|
||||
{"kArgsNormal", 0},
|
||||
{"kArgsVolPan", 1},
|
||||
{"kArgsIdVolPan", 2},
|
||||
{"kArgsXYZ", 3},
|
||||
{"kKillAll", 20},
|
||||
{"kPause", 21},
|
||||
{"kUnpause", 22},
|
||||
{"kKillInstance", 23},
|
||||
{"kTurnOnTv", 30},
|
||||
{"kTurnOffTv", 31},
|
||||
{"kUpdateSourceVolPan", 32},
|
||||
};
|
||||
|
||||
static const char SHStringTable[] =
|
||||
"\0.text"
|
||||
"\0.shstrtab"
|
||||
"\0.symtab"
|
||||
"\0.strtab"
|
||||
"\0.rel.text"
|
||||
;
|
||||
|
||||
static const uint8_t SymbolTableHeader[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xF1, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00
|
||||
};
|
19
library/tools/iff2html/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(iff2html)
|
||||
|
||||
include_directories(${LIBPNG_INCLUDE})
|
||||
include_directories(${ZLIB_INCLUDE})
|
||||
|
||||
include_directories( "${CMAKE_SOURCE_DIR}/formats")
|
||||
|
||||
set(IFF2HTML_SOURCES
|
||||
iff2html.c
|
||||
md5.c
|
||||
image.c
|
||||
opngreduc.c
|
||||
"${CMAKE_SOURCE_DIR}/formats/iff/iff.h"
|
||||
"${CMAKE_SOURCE_DIR}/formats/bmp/read_bmp.c"
|
||||
)
|
||||
|
||||
add_executable(iff2html ${IFF2HTML_SOURCES})
|
||||
target_link_libraries(iff2html iff_static FileHandler_static ${LIBPNG_LINK} ${ZLIB_LINK})
|
713
library/tools/iff2html/iff2html.c
Normal file
|
@ -0,0 +1,713 @@
|
|||
/*
|
||||
iff2html - iff web page description generator
|
||||
iff2html.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <iff/iff.h>
|
||||
#include "md5.h"
|
||||
#include "image.h"
|
||||
|
||||
#ifndef min
|
||||
#define min(x,y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef max
|
||||
#define max(x,y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
static void printsize(FILE * hFile, size_t FileSize){
|
||||
/* For our purposes, our units are best described in kB and MB, if not bytes */
|
||||
size_t temp = FileSize;
|
||||
unsigned position = 1;
|
||||
if(FileSize >= 1048576)
|
||||
fprintf(hFile, "%.1f MB (", (float)FileSize/1048576);
|
||||
else
|
||||
fprintf(hFile, "%.1f kB (", (float)FileSize/1024);
|
||||
while((temp/=1000) != 0)
|
||||
position *= 1000;
|
||||
fprintf(hFile, "%u", (unsigned) FileSize/position);
|
||||
FileSize -= (FileSize/position)*position;
|
||||
while((position/=1000) != 0){
|
||||
fprintf(hFile, ",%.3u", (unsigned) FileSize/position);
|
||||
FileSize -= (FileSize/position)*position;
|
||||
}
|
||||
fprintf(hFile, " bytes)");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned c;
|
||||
int slash;
|
||||
FILE * hFile;
|
||||
int overwrite = 0;
|
||||
char *InFile, *OutFile = NULL, *FileName, *OutDir = NULL;
|
||||
size_t FileSize;
|
||||
struct MD5Context md5c;
|
||||
unsigned char digest[16];
|
||||
uint8_t * IFFData;
|
||||
IFFFile IFFFileInfo;
|
||||
IFFChunk * ChunkData;
|
||||
|
||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: iff2html [-f] infile (outfile)\n"
|
||||
"Produce an HTML webpage describing an EA IFF file.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
"If outfile is unspecified, file.iff will output to file.html.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"iff2html is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc >= 4 && !strcmp(argv[1], "-f")){
|
||||
overwrite++;
|
||||
InFile = argv[2];
|
||||
OutFile = argv[3];
|
||||
}else if(argc == 3){
|
||||
if(!strcmp(argv[1], "-f")){
|
||||
overwrite++;
|
||||
InFile = argv[2];
|
||||
}else{
|
||||
InFile = argv[1];
|
||||
OutFile = argv[2];
|
||||
}
|
||||
}else InFile = argv[1];
|
||||
if(OutFile == NULL){
|
||||
unsigned length = strlen(InFile);
|
||||
OutFile = malloc(max(length+2, 6));
|
||||
strcpy(OutFile, InFile);
|
||||
strcpy(max(OutFile+length-4, OutFile), ".html");
|
||||
}
|
||||
|
||||
for(c=0, slash=-1; OutFile[c]; c++)
|
||||
if(OutFile[c] == '/' || OutFile[c] == '\\') slash = c;
|
||||
if(slash >= 0){
|
||||
OutDir = malloc(slash+2);
|
||||
memcpy(OutDir, OutFile, slash+1);
|
||||
OutDir[slash+1] = 0x00;
|
||||
}else OutDir = "";
|
||||
|
||||
for(c=0, slash=-1; InFile[c]; c++)
|
||||
if(InFile[c] == '/' || InFile[c] == '\\') slash = c;
|
||||
FileName = InFile + slash + 1;
|
||||
|
||||
/****
|
||||
** Open the file and read in entire contents to memory
|
||||
*/
|
||||
|
||||
hFile = fopen(InFile, "rb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 64){
|
||||
fclose(hFile);
|
||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
IFFData = malloc(FileSize);
|
||||
if(IFFData == NULL){
|
||||
fclose(hFile);
|
||||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(fread(IFFData, 1, FileSize, hFile) != FileSize){
|
||||
fclose(hFile);
|
||||
printf("%sThe input file could not be read.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
|
||||
/****
|
||||
** Load header information
|
||||
*/
|
||||
|
||||
if(!iff_create(&IFFFileInfo)){
|
||||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(&IFFFileInfo, IFFData, FileSize)){
|
||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****
|
||||
** Load entry information
|
||||
*/
|
||||
|
||||
if(!iff_enumerate_chunks(&IFFFileInfo, IFFData+64, FileSize-64)){
|
||||
printf("%sChunk data is corrupt.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate the MD5, and then we can free the IFF data because we're done with it */
|
||||
MD5Init(&md5c);
|
||||
MD5Update(&md5c, IFFData, FileSize);
|
||||
MD5Final(digest, &md5c);
|
||||
free(IFFData);
|
||||
|
||||
for(c = 0, ChunkData = IFFFileInfo.Chunks; c < IFFFileInfo.ChunkCount; c++, ChunkData++)
|
||||
iff_parse_chunk(ChunkData, ChunkData->Data);
|
||||
|
||||
/****
|
||||
** Open the output file and write the header
|
||||
*/
|
||||
if(!overwrite){
|
||||
hFile = fopen(OutFile, "rb");
|
||||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile);
|
||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y'){
|
||||
printf("\nAborted.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
hFile = fopen(OutFile, "wb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe output file could not be opened for writing.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****
|
||||
** We're splitting fprintf by line to guarantee compatibility;
|
||||
** even C99 compilers are only required to support 4096 byte strings in printf()-related functions
|
||||
*/
|
||||
fprintf(hFile,
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
|
||||
fprintf(hFile, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\">\n");
|
||||
fprintf(hFile, "<head>\n");
|
||||
fprintf(hFile, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />\n");
|
||||
fprintf(hFile, "<meta http-equiv=\"Content-Style-Type\" content=\"text/css; charset=iso-8859-1\" />\n");
|
||||
fprintf(hFile, "<meta http-equiv=\"Content-Language\" content=\"en\" />\n");
|
||||
fprintf(hFile, "<meta name=\"description\" content=\"%s (iff2html)\" />\n", FileName);
|
||||
fprintf(hFile, "<meta name=\"generator\" content=\"iff2html\" />\n");
|
||||
fprintf(hFile, "<title>%s (iff2html)</title>\n", FileName);
|
||||
fprintf(hFile, "<style type=\"text/css\" media=\"all\">\n");
|
||||
fprintf(hFile, "html, body {\n");
|
||||
fprintf(hFile, " background: #fff;\n");
|
||||
fprintf(hFile, " color: #000;\n");
|
||||
fprintf(hFile, " font-family: sans-serif;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "a:link, a:visited, a:hover, a:active { color: #00f; }\n");
|
||||
fprintf(hFile, "a:link, a:visited { text-decoration: none; }\n");
|
||||
fprintf(hFile, "a:hover, a:active { text-decoration: underline; }\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "#attributes {\n");
|
||||
fprintf(hFile, " border-left: 2px solid #888; padding-left: 4px; margin-bottom: 1em;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "#toc {\n");
|
||||
fprintf(hFile, " display: table-cell;\n");
|
||||
fprintf(hFile, " margin-top: 1em;\n");
|
||||
fprintf(hFile, " background: #eee; border: 1px solid #bbb;\n");
|
||||
fprintf(hFile, " padding: .25em;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "#toc div {\n");
|
||||
fprintf(hFile, " border-bottom: 1px solid #aaa;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "#toc ul {\n");
|
||||
fprintf(hFile, " list-style-type: none;\n");
|
||||
fprintf(hFile, " padding: 0;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "ul ul {\n");
|
||||
fprintf(hFile, " padding: 2em;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "h2 {\n");
|
||||
fprintf(hFile, " border-bottom: 1px solid #888;\n");
|
||||
fprintf(hFile, " margin: 2em 0 0.25em 0;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "h2 a {\n");
|
||||
fprintf(hFile, " font-size: 9pt;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "table {\n");
|
||||
fprintf(hFile, " border: 1px #aaa solid;\n");
|
||||
fprintf(hFile, " border-collapse: collapse;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "th, td {\n");
|
||||
fprintf(hFile, " border: 1px #aaa solid;\n");
|
||||
fprintf(hFile, " padding: 0.2em;\n");
|
||||
fprintf(hFile, " white-space: pre-wrap;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, ".center {\n");
|
||||
fprintf(hFile, " margin: auto auto;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, ".centerall * {\n");
|
||||
fprintf(hFile, " text-align: center;\n");
|
||||
fprintf(hFile, " vertical-align: middle;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, ".palette td, .palette th {\n");
|
||||
fprintf(hFile, " border: none;\n");
|
||||
fprintf(hFile, " width: 16px;\n");
|
||||
fprintf(hFile, " height: 16px;\n");
|
||||
fprintf(hFile, " font-size: 12px;\n");
|
||||
fprintf(hFile, " line-height: 16px;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, ".palette td[title] {\n");
|
||||
fprintf(hFile, " border: 1px solid #000;\n");
|
||||
fprintf(hFile, " cursor: help;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "#footer {\n");
|
||||
fprintf(hFile, " margin-top: 2em;\n");
|
||||
fprintf(hFile, " padding-bottom: 0.5em;\n");
|
||||
fprintf(hFile, " text-align: center;\n");
|
||||
fprintf(hFile, "}\n");
|
||||
fprintf(hFile, "</style>\n");
|
||||
fprintf(hFile, "</head>\n");
|
||||
fprintf(hFile, "<body>\n");
|
||||
fprintf(hFile, "<h1>%s</h1>\n", FileName);
|
||||
fprintf(hFile, "<div id=\"attributes\">\n");
|
||||
fprintf(hFile, "<div>");
|
||||
for(c=0; c<16; c++)
|
||||
fprintf(hFile, "%.2x", digest[c]);
|
||||
fprintf(hFile, " (md5), ");
|
||||
printsize(hFile, FileSize);
|
||||
fprintf(hFile, "</div>\n");
|
||||
fprintf(hFile, "<div>Dumped by iff2html.</div></div>\n");
|
||||
fprintf(hFile, "\n");
|
||||
fprintf(hFile, "<div id=\"toc\"><div><b>Contents</b> – %u chunks</div>\n", IFFFileInfo.ChunkCount);
|
||||
fprintf(hFile, "<ul>\n");
|
||||
for(c=1, ChunkData = IFFFileInfo.Chunks; c <= IFFFileInfo.ChunkCount; c++, ChunkData++)
|
||||
fprintf(hFile, "<li><a href=\"#chunk%u_%.4x\">%u [%s] (%.4X)%s%s</a></li>\n",
|
||||
c, ChunkData->ChunkID, c, ChunkData->Type, ChunkData->ChunkID,
|
||||
(ChunkData->Label[0] != 0x00) ? " – " : "", ChunkData->Label);
|
||||
fprintf(hFile, "</ul>\n");
|
||||
fprintf(hFile, "</div>\n");
|
||||
fprintf(hFile, "\n");
|
||||
|
||||
for(c=0, ChunkData = IFFFileInfo.Chunks; c < IFFFileInfo.ChunkCount; c++, ChunkData++){
|
||||
fprintf(hFile, "<h2 id=\"chunk%u_%.4x\">%u [%s] (%.4X)%s%s <a href=\"#chunk%u_%.4x\">(Jump)</a></h2>\n",
|
||||
c+1, ChunkData->ChunkID, c+1, ChunkData->Type, ChunkData->ChunkID,
|
||||
(ChunkData->Label[0] != 0x00) ? " – " : "", ChunkData->Label,
|
||||
c+1, ChunkData->ChunkID);
|
||||
fprintf(hFile, "<div>\n");
|
||||
|
||||
if(ChunkData->FormattedData == NULL){
|
||||
int success = 0;
|
||||
/* The iff library does not parse BMP_ or FBMP chunks */
|
||||
if(!strcmp(ChunkData->Type, "BMP_") || !strcmp(ChunkData->Type, "FBMP")){
|
||||
int bmp = !strcmp(ChunkData->Type, "BMP_");
|
||||
size_t Width, Height;
|
||||
char filename[32];
|
||||
sprintf(filename, "%s%s_%u_%.4x.png", OutDir, bmp ? "bmp" : "fbmp", c+1, ChunkData->ChunkID);
|
||||
|
||||
if(WritePNG(filename, ChunkData, 0, NULL, &Width, &Height)){
|
||||
fprintf(hFile, "<table class=\"center centerall\">\n");
|
||||
fprintf(hFile, "<tr><th>Image</th></tr>\n");
|
||||
fprintf(hFile, "<tr><td><img src=\"%s_%u_%.4x.png\" width=\"%u\" height=\"%u\" alt=\"\" /></td></tr>\n",
|
||||
bmp ? "bmp" : "fbmp", c+1, ChunkData->ChunkID, (unsigned) Width, (unsigned) Height);
|
||||
fprintf(hFile, "</table>\n");
|
||||
success++;
|
||||
}
|
||||
}
|
||||
if(!success)
|
||||
fprintf(hFile, "The contents of this chunk could not be parsed.\n");
|
||||
}else if(!strcmp(ChunkData->Type, "STR#") ||
|
||||
!strcmp(ChunkData->Type, "CTSS") ||
|
||||
!strcmp(ChunkData->Type, "FAMs") ||
|
||||
!strcmp(ChunkData->Type, "TTAs") ||
|
||||
!strcmp(ChunkData->Type, "CST") ){
|
||||
/****
|
||||
** STR# parsing
|
||||
*/
|
||||
|
||||
IFFString * StringData = ChunkData->FormattedData;
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Format:</td><td>");
|
||||
switch(StringData->Format){
|
||||
case 0: fprintf(hFile, "<tt>00 00</tt> (0)"); break;
|
||||
case -1: fprintf(hFile, "<tt>FF FF</tt> (−1)"); break;
|
||||
case -2: fprintf(hFile, "<tt>FE FF</tt> (−2)"); break;
|
||||
case -3: fprintf(hFile, "<tt>FD FF</tt> (−3)"); break;
|
||||
case -4: fprintf(hFile, "<tt>FC FF</tt> (−4)"); break;
|
||||
default: fprintf(hFile, "Unrecognized"); break;
|
||||
}
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(StringData->Format >= -4 && StringData->Format <= 0){
|
||||
unsigned LanguageSet;
|
||||
const char * LanguageStrings[] = {
|
||||
"English (US)",
|
||||
"English (International)",
|
||||
"French",
|
||||
"German",
|
||||
"Italian",
|
||||
"Spanish",
|
||||
"Dutch",
|
||||
"Danish",
|
||||
"Swedish",
|
||||
"Norwegian",
|
||||
"Finnish",
|
||||
"Hebrew",
|
||||
"Russian",
|
||||
"Portuguese",
|
||||
"Japanese",
|
||||
"Polish",
|
||||
"Simplified Chinese",
|
||||
"Traditional Chinese",
|
||||
"Thai",
|
||||
"Korean"
|
||||
};
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>Language</th><th colspan=\"3\">String pairs</th></tr>\n");
|
||||
|
||||
for(LanguageSet=0; LanguageSet<20; LanguageSet++){
|
||||
IFFStringPair * Pair;
|
||||
unsigned PairIndex;
|
||||
if(StringData->LanguageSets[LanguageSet].PairCount == 0)
|
||||
continue;
|
||||
|
||||
fprintf(hFile, "<tr><td rowspan=\"%u\">%s</td>\n", StringData->LanguageSets[LanguageSet].PairCount,
|
||||
LanguageStrings[LanguageSet]);
|
||||
for(PairIndex=1, Pair = StringData->LanguageSets[LanguageSet].Pairs;
|
||||
PairIndex <= StringData->LanguageSets[LanguageSet].PairCount; PairIndex++, Pair++){
|
||||
if(PairIndex != 1)
|
||||
fprintf(hFile, "<tr>");
|
||||
fprintf(hFile, "<td>%u</td><td>%s</td><td>%s</td></tr>\n", PairIndex,
|
||||
(Pair->Key) != NULL ? Pair->Key : "",
|
||||
(Pair->Value) != NULL ? Pair->Value : "");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else if(!strcmp(ChunkData->Type, "CATS")){
|
||||
/****
|
||||
** Regular string pair
|
||||
*/
|
||||
|
||||
IFFStringPair * Pair = ChunkData->FormattedData;
|
||||
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>Key</th><th>Value</th></tr>\n");
|
||||
fprintf(hFile, "<tr><td>%s</td><td>%s</td></tr>\n",
|
||||
(Pair->Key) != NULL ? Pair->Key : "",
|
||||
(Pair->Value) != NULL ? Pair->Value : "");
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "FWAV") || !strcmp(ChunkData->Type, "GLOB")){
|
||||
/****
|
||||
** Regular string
|
||||
*/
|
||||
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>String</th></tr>\n");
|
||||
fprintf(hFile, "<tr><td>%s</td></tr>\n", ChunkData->FormattedData ? (char*) ChunkData->FormattedData : "");
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "BCON")){
|
||||
/****
|
||||
** BCON parsing
|
||||
*/
|
||||
|
||||
IFF_BCON * BCONData = ChunkData->FormattedData;
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Flags:</td><td><tt>%02X</tt> (%u)</td></tr>\n", BCONData->Flags, BCONData->Flags);
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(BCONData->ConstantCount > 0){
|
||||
unsigned i;
|
||||
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Constant Value</th></tr>\n");
|
||||
for(i=0; i<BCONData->ConstantCount; i++)
|
||||
fprintf(hFile, "<tr><td>%u</td><td>%u</td></tr>\n", i+1, BCONData->Constants[i]);
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else if(!strcmp(ChunkData->Type, "FCNS")){
|
||||
/****
|
||||
** FCNS parsing
|
||||
*/
|
||||
|
||||
IFFConstantList * List = ChunkData->FormattedData;
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", List->Version);
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(List->ConstantCount > 0){
|
||||
IFFConstant * Constant;
|
||||
unsigned i;
|
||||
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Name</th><th>Value</th><th>Description</th></tr>\n");
|
||||
for(i=0, Constant=List->Constants; i<List->ConstantCount; i++, Constant++)
|
||||
fprintf(hFile, "<tr><td>%u</td><td>%s</td><td>%g</td><td>%s</td></tr>\n",
|
||||
i+1,
|
||||
Constant->Name ? Constant->Name : "",
|
||||
Constant->Value,
|
||||
Constant->Description ? Constant->Description : "");
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else if(!strcmp(ChunkData->Type, "TMPL")){
|
||||
/****
|
||||
** TMPL parsing
|
||||
*/
|
||||
|
||||
IFFTemplate * Template = ChunkData->FormattedData;
|
||||
IFFTemplateField * Field;
|
||||
unsigned i;
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Name</th><th>Type</th>\n");
|
||||
for(i=0, Field=Template->Fields; i<Template->FieldCount; i++, Field++)
|
||||
fprintf(hFile, "<tr><td>%u</td><td>%s</td><td>%s</td></tr>\n",
|
||||
i+1,
|
||||
Field->Name ? Field->Name : "",
|
||||
Field->Type ? Field->Type : "");
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "TRCN")){
|
||||
/****
|
||||
** TRCN parsing
|
||||
*/
|
||||
|
||||
IFFRangeSet * RangeSet = ChunkData->FormattedData;
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", RangeSet->Version);
|
||||
fprintf(hFile, "</table>\n");
|
||||
if(RangeSet->RangeCount > 0){
|
||||
unsigned i;
|
||||
IFFRangeEntry * Range;
|
||||
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">In use</th><th>Default value</th><th>Name</th>"
|
||||
"<th>Comment</th><th>Range is enforced</th><th>Minimum</th><th>Maximum</th></tr>\n");
|
||||
for(i=0, Range=RangeSet->Ranges; i<RangeSet->RangeCount; i++, Range++)
|
||||
fprintf(hFile,
|
||||
"<tr><td>%u</td><td>%s</td><td>%u</td><td>%s</td><td>%s</td><td>%s</td><td>%u</td><td>%u</td></tr>\n",
|
||||
i+1,
|
||||
Range->IsUsed ? "Yes" : "No", Range->DefaultValue,
|
||||
Range->Name ? Range->Name : "",
|
||||
Range->Comment ? Range->Comment : "",
|
||||
Range->Enforced ? "Yes" : "No",
|
||||
Range->RangeMin, Range->RangeMax);
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else if(!strcmp(ChunkData->Type, "PALT")){
|
||||
/****
|
||||
** PALT parsing
|
||||
*/
|
||||
|
||||
IFFPalette * Palette = ChunkData->FormattedData;
|
||||
uint8_t * Data = Palette->Data;
|
||||
unsigned i, j;
|
||||
|
||||
fprintf(hFile, "<table class=\"center palette\" border=\"0\">\n");
|
||||
fprintf(hFile, "<tr><th></th>");
|
||||
for(i=0; i<16; i++) fprintf(hFile, "<th>%X</th>", i);
|
||||
fprintf(hFile, "</tr>\n");
|
||||
for(i=0; i<16; i++){
|
||||
fprintf(hFile, "<tr><th>%X</th>", i);
|
||||
for(j=0; j<16; j++){
|
||||
if(i*16 + j < Palette->ColorCount){
|
||||
unsigned red = *(Data++);
|
||||
unsigned green = *(Data++);
|
||||
unsigned blue = *(Data++);
|
||||
|
||||
fprintf(hFile, "\n<td style=\"background:#%.2x%.2x%.2x\" title=\"%u: #%.2x%.2x%.2x\"></td>",
|
||||
red, green, blue, i*16 + j, red, green, blue);
|
||||
}else
|
||||
fprintf(hFile, "\n<td></td>");
|
||||
}
|
||||
fprintf(hFile, "</tr>\n");
|
||||
}
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "SPR#") || !strcmp(ChunkData->Type, "SPR2")){
|
||||
/****
|
||||
** SPR# and SPR2 parsing
|
||||
*/
|
||||
|
||||
int spr1 = !strcmp(ChunkData->Type, "SPR#");
|
||||
IFFSpriteList * SpriteList = ChunkData->FormattedData;
|
||||
IFFChunk * Palette = NULL;
|
||||
IFFPalette BlankPalette;
|
||||
IFFPalette * PaletteData;
|
||||
unsigned i;
|
||||
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", SpriteList->Version);
|
||||
fprintf(hFile, "<tr><td>Palette ID:</td><td>%.4X</td></tr>\n", SpriteList->PaletteID);
|
||||
fprintf(hFile, "</table>\n");
|
||||
|
||||
if(SpriteList->PaletteID < 0xFFFF){
|
||||
Palette = iff_find_chunk(&IFFFileInfo, "PALT", SpriteList->PaletteID);
|
||||
if(!Palette || !Palette->FormattedData) Palette = iff_find_chunk(&IFFFileInfo, "PALT", ChunkData->ChunkID);
|
||||
if(!Palette || !Palette->FormattedData) Palette = iff_find_chunk(&IFFFileInfo, "PALT", -1);
|
||||
}
|
||||
if(!Palette || !Palette->FormattedData){
|
||||
memset(&BlankPalette, 0, sizeof(IFFPalette));
|
||||
BlankPalette.Version = 1;
|
||||
BlankPalette.ColorCount = 256;
|
||||
PaletteData = &BlankPalette;
|
||||
}else PaletteData = Palette->FormattedData;
|
||||
|
||||
fprintf(hFile, "<table class=\"center centerall\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Sprite</th>");
|
||||
if(!spr1) fprintf(hFile, "<th>Z-Buffer</th>");
|
||||
fprintf(hFile, "</tr>\n");
|
||||
for(i=0; i<SpriteList->SpriteCount; i++){
|
||||
IFFSprite * Sprite = &SpriteList->Sprites[i];
|
||||
char filename[32];
|
||||
sprintf(filename, "%s%s_%u_%.4x_%u.png", OutDir, spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1);
|
||||
|
||||
fprintf(hFile, "<tr><td>%u</td><td", i+1);
|
||||
if(Sprite->IndexData && iff_depalette(Sprite, PaletteData)){
|
||||
WritePNG(filename, NULL, 0, Sprite, NULL, NULL);
|
||||
fprintf(hFile, "><img src=\"%s_%u_%.4x_%u.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
|
||||
spr1 ? "spr1" : "spr2", c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height);
|
||||
if(!spr1){
|
||||
sprintf(filename, "%sspr2_%u_%.4x_%u_z.png", OutDir, c+1, ChunkData->ChunkID, i+1);
|
||||
if(Sprite->ZBuffer){
|
||||
WritePNG(filename, NULL, 1, Sprite, NULL, NULL);
|
||||
fprintf(hFile, "</td><td><img src=\"spr2_%u_%.4x_%u_z.png\" width=\"%u\" height=\"%u\" alt=\"\" />",
|
||||
c+1, ChunkData->ChunkID, i+1, Sprite->Width, Sprite->Height);
|
||||
}else
|
||||
fprintf(hFile, "None provided");
|
||||
}
|
||||
}else
|
||||
fprintf(hFile, Sprite->InvalidDimensions ? "%sBlank sprite" : "%sThis sprite cannot be displayed.",
|
||||
!spr1 ? " colspan=\"2\">" : ">");
|
||||
fprintf(hFile, "</td></tr>\n");
|
||||
}
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "DGRP")){
|
||||
/****
|
||||
** DGRP parsing
|
||||
*/
|
||||
|
||||
IFFDrawGroup * Group = ChunkData->FormattedData;
|
||||
IFFDrawAngle * Angle;
|
||||
IFFSpriteInfo * Sprite;
|
||||
unsigned i,j;
|
||||
const char * Zooms[] = {"Far", "Middle", "Close"};
|
||||
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Group->Version);
|
||||
fprintf(hFile, "</table>\n");
|
||||
fprintf(hFile, "<br />\n");
|
||||
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th>Direction</th><th>Zoom</th><th colspan=\"6\">Sprite</th></tr>\n");
|
||||
for(i=0, Angle=Group->DrawAngles; i<12; i++, Angle++){
|
||||
const char * Direction =
|
||||
(Angle->Direction == IFFDIRECTION_NORTHEAST) ? "North east" :
|
||||
(Angle->Direction == IFFDIRECTION_SOUTHEAST) ? "South east" :
|
||||
(Angle->Direction == IFFDIRECTION_NORTHWEST) ? "North west" :
|
||||
"South west";
|
||||
|
||||
if(Angle->SpriteCount){
|
||||
fprintf(hFile,
|
||||
"<tr><td rowspan=\"%u\">%s</td><td rowspan=\"%u\">%s</td>"
|
||||
"<th>#</th><th>Type</th><th>Chunk ID</th><th>Sprite index</th>"
|
||||
"<th>Flags</th><th>Sprite offset</th><th>Object offset</th></tr>\n",
|
||||
1+Angle->SpriteCount, Direction, 1+Angle->SpriteCount, Zooms[Angle->Zoom-1]);
|
||||
for(j=0, Sprite = Angle->SpriteInfo; j<Angle->SpriteCount; j++, Sprite++)
|
||||
fprintf(hFile, "<tr><td>%u</td><td>%u</td><td>%.4X</td><td>%u</td><td>%u</td>"
|
||||
"<td>(%+d,%+d)</td><td>(%+g,%+g,%+g)</td></tr>",
|
||||
j+1, Sprite->Type, Sprite->ChunkID, Sprite->SpriteIndex, Sprite->Flags,
|
||||
Sprite->SpriteX, Sprite->SpriteY, Sprite->ObjectX, Sprite->ObjectY, Sprite->ObjectZ);
|
||||
|
||||
}else{
|
||||
fprintf(hFile, "<tr><td>%s</td><td>%s</td><td>None specified</td></tr>", Direction, Zooms[Angle->Zoom-1]);
|
||||
}
|
||||
}
|
||||
fprintf(hFile, "</table>\n");
|
||||
}else if(!strcmp(ChunkData->Type, "BHAV")){
|
||||
/****
|
||||
** BHAV parsing
|
||||
*/
|
||||
|
||||
IFFBehavior * Behavior = ChunkData->FormattedData;
|
||||
IFFInstruction * Instruction;
|
||||
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Behavior->Version);
|
||||
fprintf(hFile, "<tr><td>Type:</td><td>%u</td></tr>\n", Behavior->Type);
|
||||
fprintf(hFile, "<tr><td>Arguments:</td><td>%u</td></tr>\n", Behavior->ArgumentCount);
|
||||
fprintf(hFile, "<tr><td>Locals:</td><td>%u</td></tr>\n", Behavior->LocalCount);
|
||||
fprintf(hFile, "<tr><td>Flags:</td><td>%.4X</td></tr>\n", Behavior->Flags);
|
||||
fprintf(hFile, "</table>\n");
|
||||
|
||||
if(Behavior->InstructionCount > 0){
|
||||
unsigned i;
|
||||
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Opcode</th><th>T-Dest</th><th>F-Dest</th><th>Operand data</th></tr>\n");
|
||||
for(i=0, Instruction = Behavior->Instructions; i<Behavior->InstructionCount; i++, Instruction++)
|
||||
fprintf(hFile, "<tr><td>%u</td><td><tt>%.4X</tt></td><td>%u</td><td>%u</td>"
|
||||
"<td><tt>%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X</tt></td></tr>\n",
|
||||
i, Instruction->Opcode, Instruction->TDest, Instruction->FDest,
|
||||
Instruction->Operands[0], Instruction->Operands[1],
|
||||
Instruction->Operands[2], Instruction->Operands[3],
|
||||
Instruction->Operands[4], Instruction->Operands[5],
|
||||
Instruction->Operands[6], Instruction->Operands[7]);
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else if(!strcmp(ChunkData->Type, "OBJf")){
|
||||
/****
|
||||
** OBJf parsing
|
||||
*/
|
||||
|
||||
IFFFunctionTable * Table = ChunkData->FormattedData;
|
||||
fprintf(hFile, "<table>\n");
|
||||
fprintf(hFile, "<tr><td>Version:</td><td>%u</td></tr>\n", Table->Version);
|
||||
fprintf(hFile, "</table>\n");
|
||||
|
||||
if(Table->FunctionCount > 0){
|
||||
unsigned i;
|
||||
|
||||
fprintf(hFile, "<br />\n");
|
||||
fprintf(hFile, "<table class=\"center\">\n");
|
||||
fprintf(hFile, "<tr><th colspan=\"2\">Condition function</th><th>Action function</th></tr>\n");
|
||||
for(i=0; i<Table->FunctionCount; i++)
|
||||
fprintf(hFile,
|
||||
"<tr><td>%u</td><td>%.4X</td><td>%.4X</td></tr>\n",
|
||||
i+1, Table->Functions[i].ConditionID, Table->Functions[i].ActionID);
|
||||
fprintf(hFile, "</table>\n");
|
||||
}
|
||||
}else{
|
||||
fprintf(hFile, "The contents of this chunk cannot be shown on this page.\n");
|
||||
}
|
||||
|
||||
fprintf(hFile, "</div>\n\n");
|
||||
}
|
||||
iff_delete(&IFFFileInfo);
|
||||
|
||||
fprintf(hFile,
|
||||
"<div id=\"footer\">This page was generated by the use of <a href=\"http://www.niotso.org/\">iff2html</a>.\n");
|
||||
fprintf(hFile, "The content of this page may be subject to copyright by the author(s) of the original iff file.</div>\n");
|
||||
fprintf(hFile, "</body>\n");
|
||||
fprintf(hFile, "</html>");
|
||||
fclose(hFile);
|
||||
|
||||
printf("Wrote contents to '%s'.\n", OutFile);
|
||||
return 0;
|
||||
}
|
149
library/tools/iff2html/image.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
iff2html - iff web page description generator
|
||||
image.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iff/iff.h>
|
||||
#include <bmp/read_bmp.h>
|
||||
#include <png.h>
|
||||
#include <setjmp.h> /* Used for libpng */
|
||||
#include "opngreduc.h"
|
||||
|
||||
int WritePNG(const char * OutName, const IFFChunk * ChunkData, int ZBuffer,
|
||||
const IFFSprite * Sprite, size_t * Width, size_t * Height){
|
||||
FILE * hFile;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytep * row_pointers;
|
||||
unsigned i;
|
||||
|
||||
struct {
|
||||
size_t Width;
|
||||
size_t Height;
|
||||
uint8_t * Data;
|
||||
} Image;
|
||||
|
||||
/* We must swap from BGR to RGB; this cannot be done with libpng when you use
|
||||
** opng_reduce_image due to the state that it leaves png_ptr in */
|
||||
|
||||
if(ChunkData){
|
||||
/* BMP_ or FBMP chunk */
|
||||
bmpheader_t BMPHeader;
|
||||
|
||||
if(!bmp_read_header(&BMPHeader, ChunkData->Data, ChunkData->Size))
|
||||
return 0;
|
||||
|
||||
Image.Data = malloc(BMPHeader.DecompressedSize);
|
||||
if(Image.Data == NULL)
|
||||
return 0;
|
||||
if(!bmp_read_data(&BMPHeader, ChunkData->Data, Image.Data)){
|
||||
free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Image.Width = BMPHeader.biWidth;
|
||||
Image.Height = BMPHeader.biHeight;
|
||||
|
||||
for(i=0; i<Image.Width*Image.Height; i++){
|
||||
uint8_t temp = Image.Data[i*3 + 0];
|
||||
Image.Data[i*3 + 0] = Image.Data[i*3 + 2];
|
||||
Image.Data[i*3 + 2] = temp;
|
||||
}
|
||||
}else{
|
||||
/* SPR# or SPR2 sprite */
|
||||
Image.Width = Sprite->Width;
|
||||
Image.Height = Sprite->Height;
|
||||
Image.Data = (!ZBuffer) ? Sprite->BGRA32Data : Sprite->ZBuffer;
|
||||
|
||||
if(!ZBuffer){
|
||||
for(i=0; i<Image.Width*Image.Height; i++){
|
||||
uint8_t temp = Image.Data[i*4 + 0];
|
||||
Image.Data[i*4 + 0] = Image.Data[i*4 + 2];
|
||||
Image.Data[i*4 + 2] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
row_pointers = malloc(Image.Height * sizeof(png_bytep));
|
||||
if(row_pointers == NULL){
|
||||
if(ChunkData) free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<Image.Height; i++)
|
||||
row_pointers[i] = Image.Data + Image.Width*((ChunkData) ? 3*(Image.Height-i-1) : ((!ZBuffer)?4:1)*i);
|
||||
|
||||
/****
|
||||
** PNG handling
|
||||
*/
|
||||
|
||||
/* Initialization */
|
||||
hFile = fopen(OutName, "wb");
|
||||
if(hFile == NULL){
|
||||
free(row_pointers);
|
||||
if(ChunkData) free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if(png_ptr == NULL){
|
||||
fclose(hFile);
|
||||
free(row_pointers);
|
||||
if(ChunkData) free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if(info_ptr == NULL){
|
||||
png_destroy_write_struct(&png_ptr, NULL);
|
||||
fclose(hFile);
|
||||
free(row_pointers);
|
||||
if(ChunkData) free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
if(setjmp(png_jmpbuf(png_ptr))){
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(hFile);
|
||||
free(row_pointers);
|
||||
if(ChunkData) free(Image.Data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, hFile);
|
||||
|
||||
png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);
|
||||
png_set_compression_level(png_ptr, 9);
|
||||
png_set_compression_mem_level(png_ptr, 9);
|
||||
png_set_compression_window_bits(png_ptr, 15);
|
||||
png_set_compression_buffer_size(png_ptr, 32768);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr, Image.Width, Image.Height, 8,
|
||||
ChunkData ? PNG_COLOR_TYPE_RGB : (!ZBuffer) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_GRAY,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_set_rows(png_ptr, info_ptr, row_pointers);
|
||||
opng_reduce_image(png_ptr, info_ptr, OPNG_REDUCE_ALL);
|
||||
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(hFile);
|
||||
free(row_pointers);
|
||||
|
||||
if(ChunkData){
|
||||
free(Image.Data);
|
||||
*Width = Image.Width;
|
||||
*Height = Image.Height;
|
||||
}
|
||||
return 1;
|
||||
}
|
20
library/tools/iff2html/image.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
iff2html - iff web page description generator
|
||||
image.h - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
int WritePNG(const char * OutName, const IFFChunk * ChunkData, int ZBuffer,
|
||||
const IFFSprite * Sprite, size_t * Width, size_t * Height);
|
255
library/tools/iff2html/md5.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
/* Brutally hacked by John Walker back from ANSI C to K&R (no
|
||||
prototypes) to maintain the tradition that Netfone will compile
|
||||
with Sun's original "cc". */
|
||||
|
||||
#include <memory.h> /* for memcpy() */
|
||||
#include "md5.h"
|
||||
|
||||
#ifndef HIGHFIRST
|
||||
#define byteReverse(buf, len) /* Nothing */
|
||||
#else
|
||||
/*
|
||||
* Note: this code is harmless on little-endian machines.
|
||||
*/
|
||||
void byteReverse(buf, longs)
|
||||
unsigned char *buf; unsigned longs;
|
||||
{
|
||||
uint32 t;
|
||||
do {
|
||||
t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
|
||||
((unsigned) buf[1] << 8 | buf[0]);
|
||||
*(uint32 *) buf = t;
|
||||
buf += 4;
|
||||
} while (--longs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void MD5Init(ctx)
|
||||
struct MD5Context *ctx;
|
||||
{
|
||||
ctx->buf[0] = 0x67452301;
|
||||
ctx->buf[1] = 0xefcdab89;
|
||||
ctx->buf[2] = 0x98badcfe;
|
||||
ctx->buf[3] = 0x10325476;
|
||||
|
||||
ctx->bits[0] = 0;
|
||||
ctx->bits[1] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void MD5Update(ctx, buf, len)
|
||||
struct MD5Context *ctx; unsigned char *buf; unsigned len;
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
/* Update bitcount */
|
||||
|
||||
t = ctx->bits[0];
|
||||
if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
|
||||
ctx->bits[1]++; /* Carry from low to high */
|
||||
ctx->bits[1] += len >> 29;
|
||||
|
||||
t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
|
||||
|
||||
/* Handle any leading odd-sized chunks */
|
||||
|
||||
if (t) {
|
||||
unsigned char *p = (unsigned char *) ctx->in.c + t;
|
||||
|
||||
t = 64 - t;
|
||||
if (len < t) {
|
||||
memcpy(p, buf, len);
|
||||
return;
|
||||
}
|
||||
memcpy(p, buf, t);
|
||||
byteReverse(ctx->in.c, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *) ctx->in.c);
|
||||
buf += t;
|
||||
len -= t;
|
||||
}
|
||||
/* Process data in 64-byte chunks */
|
||||
|
||||
while (len >= 64) {
|
||||
memcpy(ctx->in.c, buf, 64);
|
||||
byteReverse(ctx->in.c, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *) ctx->in.c);
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
|
||||
memcpy(ctx->in.c, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup - pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
void MD5Final(digest, ctx)
|
||||
unsigned char digest[16]; struct MD5Context *ctx;
|
||||
{
|
||||
unsigned count;
|
||||
unsigned char *p;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
count = (ctx->bits[0] >> 3) & 0x3F;
|
||||
|
||||
/* Set the first char of padding to 0x80. This is safe since there is
|
||||
always at least one byte free */
|
||||
p = ctx->in.c + count;
|
||||
*p++ = 0x80;
|
||||
|
||||
/* Bytes of padding needed to make 64 bytes */
|
||||
count = 64 - 1 - count;
|
||||
|
||||
/* Pad out to 56 mod 64 */
|
||||
if (count < 8) {
|
||||
/* Two lots of padding: Pad the first block to 64 bytes */
|
||||
memset(p, 0, count);
|
||||
byteReverse(ctx->in.c, 16);
|
||||
MD5Transform(ctx->buf, (uint32 *) ctx->in.c);
|
||||
|
||||
/* Now fill the next block with 56 bytes */
|
||||
memset(ctx->in.c, 0, 56);
|
||||
} else {
|
||||
/* Pad block to 56 bytes */
|
||||
memset(p, 0, count - 8);
|
||||
}
|
||||
byteReverse(ctx->in.c, 14);
|
||||
|
||||
/* Append length in bits and transform */
|
||||
ctx->in.i[14] = ctx->bits[0];
|
||||
ctx->in.i[15] = ctx->bits[1];
|
||||
|
||||
MD5Transform(ctx->buf, (uint32 *) ctx->in.c);
|
||||
byteReverse((unsigned char *) ctx->buf, 4);
|
||||
memcpy(digest, ctx->buf, 16);
|
||||
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
|
||||
}
|
||||
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
void MD5Transform(buf, in)
|
||||
uint32 buf[4]; uint32 in[16];
|
||||
{
|
||||
register uint32 a, b, c, d;
|
||||
|
||||
a = buf[0];
|
||||
b = buf[1];
|
||||
c = buf[2];
|
||||
d = buf[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
|
||||
|
||||
buf[0] += a;
|
||||
buf[1] += b;
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
57
library/tools/iff2html/md5.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
/* The following tests optimise behaviour on little-endian
|
||||
machines, where there is no need to reverse the byte order
|
||||
of 32 bit words in the MD5 computation. By default,
|
||||
HIGHFIRST is defined, which indicates we're running on a
|
||||
big-endian (most significant byte first) machine, on which
|
||||
the byteReverse function in md5.c must be invoked. However,
|
||||
byteReverse is coded in such a way that it is an identity
|
||||
function when run on a little-endian machine, so calling it
|
||||
on such a platform causes no harm apart from wasting time.
|
||||
If the platform is known to be little-endian, we speed
|
||||
things up by undefining HIGHFIRST, which defines
|
||||
byteReverse as a null macro. Doing things in this manner
|
||||
insures we work on new platforms regardless of their byte
|
||||
order. */
|
||||
|
||||
#define HIGHFIRST
|
||||
|
||||
#ifdef __i386__
|
||||
#undef HIGHFIRST
|
||||
#endif
|
||||
|
||||
/* On machines where "long" is 64 bits, we need to declare
|
||||
uint32 as something guaranteed to be 32 bits. */
|
||||
|
||||
#ifdef __alpha
|
||||
typedef unsigned int uint32;
|
||||
#else
|
||||
typedef unsigned long uint32;
|
||||
#endif
|
||||
|
||||
struct MD5Context {
|
||||
uint32 buf[4];
|
||||
uint32 bits[2];
|
||||
union {
|
||||
unsigned char c[64];
|
||||
uint32 i[16];
|
||||
} in;
|
||||
};
|
||||
|
||||
extern void MD5Init();
|
||||
extern void MD5Update();
|
||||
extern void MD5Final();
|
||||
extern void MD5Transform();
|
||||
|
||||
/*
|
||||
* This is needed to make RSAREF happy on some MS-DOS compilers.
|
||||
*/
|
||||
typedef struct MD5Context MD5_CTX;
|
||||
|
||||
/* Define CHECK_HARDWARE_PROPERTIES to have main,c verify
|
||||
byte order and uint32 settings. */
|
||||
#define CHECK_HARDWARE_PROPERTIES
|
||||
|
||||
#endif /* !MD5_H */
|
1311
library/tools/iff2html/opngreduc.c
Normal file
97
library/tools/iff2html/opngreduc.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* opngreduc.h - libpng extension: lossless image reductions.
|
||||
*
|
||||
* Copyright (C) 2003-2011 Cosmin Truta.
|
||||
* This software is distributed under the same licensing and warranty terms
|
||||
* as libpng.
|
||||
*
|
||||
* This code is functional, although it is still work in progress.
|
||||
* Upon completion, it will be submitted for incorporation into libpng.
|
||||
*/
|
||||
|
||||
#ifndef OPNGREDUC_H
|
||||
#define OPNGREDUC_H
|
||||
|
||||
#include <png.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef PNG_INFO_IMAGE_SUPPORTED
|
||||
|
||||
/*
|
||||
* Indicate whether the image information is valid, i.e.
|
||||
* all the required critical information is present in the png structures.
|
||||
*/
|
||||
int PNGAPI opng_validate_image(png_structp png_ptr, png_infop info_ptr);
|
||||
|
||||
#endif /* PNG_INFO_IMAGE_SUPPORTED */
|
||||
|
||||
|
||||
#ifndef OPNG_NO_IMAGE_REDUCTIONS
|
||||
#define OPNG_IMAGE_REDUCTIONS_SUPPORTED
|
||||
#endif
|
||||
|
||||
#ifdef OPNG_IMAGE_REDUCTIONS_SUPPORTED
|
||||
|
||||
#ifndef PNG_INFO_IMAGE_SUPPORTED
|
||||
#error OPNG_IMAGE_REDUCTIONS_SUPPORTED requires PNG_INFO_IMAGE_SUPPORTED
|
||||
#endif
|
||||
|
||||
#ifndef PNG_tRNS_SUPPORTED
|
||||
#error OPNG_IMAGE_REDUCTIONS_SUPPORTED requires proper transparency support
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reduce the image (bit depth + color type + palette) without
|
||||
* losing any information. The image data must be present
|
||||
* (e.g. after calling png_set_rows(), or after loading IDAT).
|
||||
*/
|
||||
png_uint_32 PNGAPI opng_reduce_image(png_structp png_ptr, png_infop info_ptr,
|
||||
png_uint_32 reductions);
|
||||
|
||||
/*
|
||||
* PNG reduction flags.
|
||||
*/
|
||||
#define OPNG_REDUCE_NONE 0x0000
|
||||
#define OPNG_REDUCE_16_TO_8 0x0001 /* discard bits 8-15 */
|
||||
#define OPNG_REDUCE_8_TO_4_2_1 0x0002 /* discard bits 4-7, 2-7 or 1-7 */
|
||||
#define OPNG_REDUCE_RGB_TO_GRAY 0x0004 /* ...also RGBA to GA */
|
||||
#define OPNG_REDUCE_STRIP_ALPHA 0x0008 /* ...and create tRNS if needed */
|
||||
#define OPNG_REDUCE_RGB_TO_PALETTE 0x0010 /* ...also RGBA to palette/tRNS */
|
||||
#define OPNG_REDUCE_PALETTE_TO_RGB 0x0020 /* TODO */
|
||||
#define OPNG_REDUCE_GRAY_TO_PALETTE 0x0040 /* ...also GA to palette/tRNS */
|
||||
#define OPNG_REDUCE_PALETTE_TO_GRAY 0x0080 /* ...also palette/tRNS to GA */
|
||||
#define OPNG_REDUCE_PALETTE_SLOW 0x0100 /* TODO: remove all sterile entries
|
||||
and reorder PLTE */
|
||||
#define OPNG_REDUCE_PALETTE_FAST 0x0200 /* remove trailing sterile entries
|
||||
only; do not reorder PLTE */
|
||||
#define OPNG_REDUCE_ANCILLARY 0x1000 /* TODO */
|
||||
|
||||
#define OPNG_REDUCE_BIT_DEPTH \
|
||||
(OPNG_REDUCE_16_TO_8 | OPNG_REDUCE_8_TO_4_2_1)
|
||||
|
||||
#define OPNG_REDUCE_COLOR_TYPE \
|
||||
(OPNG_REDUCE_RGB_TO_GRAY | OPNG_REDUCE_STRIP_ALPHA | \
|
||||
OPNG_REDUCE_RGB_TO_PALETTE | OPNG_REDUCE_PALETTE_TO_RGB | \
|
||||
OPNG_REDUCE_GRAY_TO_PALETTE | OPNG_REDUCE_PALETTE_TO_GRAY)
|
||||
|
||||
#define OPNG_REDUCE_PALETTE \
|
||||
(OPNG_REDUCE_PALETTE_SLOW | OPNG_REDUCE_PALETTE_FAST)
|
||||
|
||||
#define OPNG_REDUCE_ALL \
|
||||
(OPNG_REDUCE_BIT_DEPTH | OPNG_REDUCE_COLOR_TYPE | \
|
||||
OPNG_REDUCE_PALETTE | OPNG_REDUCE_ANCILLARY)
|
||||
|
||||
#endif /* OPNG_IMAGE_REDUCTIONS_SUPPORTED */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* OPNGREDUC_H */
|
1
library/tools/inputtest/Readme.txt
Normal file
|
@ -0,0 +1 @@
|
|||
This is for testing Windows input messages, at the moment.
|
1
library/tools/inputtest/compile.bat
Normal file
|
@ -0,0 +1 @@
|
|||
gcc -Wall -Wextra -Wabi -pedantic -m32 -o inputtest.exe inputtest.cpp -mconsole
|
96
library/tools/inputtest/inputtest.cpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
inputtest - Windows input testing
|
||||
inputtest.cpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
|
||||
switch(uMsg){
|
||||
|
||||
case WM_KEYDOWN:
|
||||
printf("[WM_KEYDOWN] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_KEYUP:
|
||||
printf("[WM_KEYUP] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_CHAR:
|
||||
printf("[WM_CHAR] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_DEADCHAR:
|
||||
printf("[WM_DEADCHAR] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_SYSKEYDOWN:
|
||||
printf("[WM_SYSKEYDOWN] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_SYSKEYUP:
|
||||
printf("[WM_SYSKEYUP] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_SYSDEADCHAR:
|
||||
printf("[WM_SYSDEADCHAR] key = %u, lParam = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_HOTKEY:
|
||||
printf("[WM_HOTKEY] keys1 = %u, keys2 = %lu\n", wParam, lParam);
|
||||
return 0;
|
||||
case WM_APPCOMMAND:
|
||||
printf("[WM_APPCOMMAND] cmd = %u, device = %u, keys = %u\n", GET_APPCOMMAND_LPARAM(lParam), GET_DEVICE_LPARAM(lParam), GET_KEYSTATE_LPARAM(lParam));
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
printf("Received message %u with wParam = %u, lParam = %lu\n", uMsg, wParam, lParam);
|
||||
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
const WNDCLASS wc = {
|
||||
0, //style
|
||||
WndProc, //lpfnWndProc
|
||||
0, //cbClsExtra
|
||||
0, //cbWndExtra
|
||||
hInstance, //hInstance
|
||||
(HICON) LoadImage(NULL, IDI_APPLICATION, //hIcon
|
||||
IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE),
|
||||
(HCURSOR) LoadImage(NULL, IDC_ARROW, //hCursor
|
||||
IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE),
|
||||
(HBRUSH) COLOR_WINDOW, //hbrBackground
|
||||
NULL, //lpszMenuName
|
||||
"INPUTTEST" //lpszClassName
|
||||
};
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
// Create the main window.
|
||||
const HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, "INPUTTEST", "Input test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, 0, 0, hInstance, NULL);
|
||||
|
||||
SetForegroundWindow(hWnd);
|
||||
SetFocus(hWnd);
|
||||
|
||||
MSG msg;
|
||||
while(GetMessage(&msg, NULL, 0, 0)){
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
8
library/tools/rtti-reader/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(rtti-reader)
|
||||
|
||||
set(RTTIREADER_SOURCES
|
||||
rtti-reader.cpp
|
||||
)
|
||||
|
||||
add_executable(rtti-reader ${RTTIREADER_SOURCES})
|
527
library/tools/rtti-reader/rtti-reader.cpp
Normal file
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
rtti-reader - The Sims Online MSVC RTTI Class Hierarchy Extractor
|
||||
rtti-reader.cpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
//For information about MSVC RTTI, read:
|
||||
//<http://www.openrce.org/articles/full_view/23>
|
||||
//<https://www.blackhat.com/presentations/bh-dc-07/Sabanal_Yason/Paper/bh-dc-07-Sabanal_Yason-WP.pdf>
|
||||
|
||||
//For information about the Windows PE header, read:
|
||||
//<https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#File_Format>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef read_int32
|
||||
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
#ifndef write_int32
|
||||
#define write_uint32(dest, src) do { \
|
||||
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
static void Shutdown_M(const char * Message);
|
||||
|
||||
struct Segment {
|
||||
size_t size, offset;
|
||||
Segment() : size(0) {}
|
||||
};
|
||||
|
||||
struct ByteReaderContext {
|
||||
size_t start, position, end;
|
||||
bool seek(size_t pos){
|
||||
if(pos > end)
|
||||
return false;
|
||||
position = pos;
|
||||
return true;
|
||||
}
|
||||
bool skip(int pos = 1){
|
||||
if(position + pos > end)
|
||||
return false;
|
||||
position += pos;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct PaddingTest {
|
||||
uint32_t A;
|
||||
uint32_t B;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct RTTIVector {
|
||||
size_t Count, SizeAllocated;
|
||||
T * Buffer;
|
||||
|
||||
void init(){
|
||||
Count = 0, SizeAllocated = sizeof(T);
|
||||
if(!(Buffer = (T*) malloc(sizeof(T))))
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
}
|
||||
T& add(){
|
||||
if((Count+1)*sizeof(T) > SizeAllocated){
|
||||
void * ptr;
|
||||
if(SizeAllocated > SIZE_MAX/2 || !(ptr = (T*) realloc(Buffer, SizeAllocated<<=1)))
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
Buffer = (T *) ptr;
|
||||
}
|
||||
|
||||
return Buffer[Count++];
|
||||
}
|
||||
};
|
||||
|
||||
struct RTTITypeDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t VTableAddress;
|
||||
uint32_t Reserved;
|
||||
} Fields;
|
||||
char * Name;
|
||||
char * UnmangledName;
|
||||
};
|
||||
|
||||
struct RTTIBaseClassDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t TypeDescriptorAddress;
|
||||
uint32_t BaseClassCount;
|
||||
uint32_t MemberOffset;
|
||||
uint32_t COLAddressOffset;
|
||||
uint32_t VTableOffset;
|
||||
uint32_t Attributes;
|
||||
} Fields;
|
||||
RTTITypeDescriptor TD;
|
||||
};
|
||||
|
||||
struct RTTIClassHierarchyDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t Reserved;
|
||||
uint32_t Attributes;
|
||||
uint32_t BaseClassCount;
|
||||
uint32_t BaseClassListAddress;
|
||||
} Fields;
|
||||
RTTIVector<RTTIBaseClassDescriptor> BCDL;
|
||||
};
|
||||
|
||||
struct RTTICompleteObjectLocator {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t Reserved;
|
||||
uint32_t Offset;
|
||||
uint32_t CDOffset;
|
||||
uint32_t TypeDescriptorAddress;
|
||||
uint32_t ClassDescriptorAddress;
|
||||
} Fields;
|
||||
uint32_t VTableAddress;
|
||||
};
|
||||
|
||||
struct RTTIClass {
|
||||
RTTIVector<RTTICompleteObjectLocator> COLL;
|
||||
RTTITypeDescriptor TD;
|
||||
RTTIClassHierarchyDescriptor CHD;
|
||||
void init(){
|
||||
COLL.init();
|
||||
CHD.BCDL.init();
|
||||
}
|
||||
bool DependsOn(const RTTIClass& X) const {
|
||||
for(uint32_t i=1; i<CHD.BCDL.Count; i++)
|
||||
if(CHD.BCDL.Buffer[i].TD.Fields.Address == X.TD.Fields.Address)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
static int Compare(const void * Aptr, const void * Bptr){
|
||||
const RTTIClass& A = *reinterpret_cast<const RTTIClass*>(Aptr);
|
||||
const RTTIClass& B = *reinterpret_cast<const RTTIClass*>(Bptr);
|
||||
|
||||
if(A.DependsOn(B)) return 1; //If A depends on B, A > B
|
||||
if(B.DependsOn(A)) return -1; //If B depends on A, B > A
|
||||
return strcmp(A.TD.UnmangledName, B.TD.UnmangledName);
|
||||
}
|
||||
};
|
||||
|
||||
struct PEFile {
|
||||
static PEFile * ptr;
|
||||
FILE * hFile;
|
||||
uint8_t * Data;
|
||||
Segment rdata, data;
|
||||
ByteReaderContext brc;
|
||||
|
||||
PEFile(const char * filename) : Data(NULL) {
|
||||
PEFile::ptr = this;
|
||||
|
||||
hFile = fopen(filename, "rb");
|
||||
if(!hFile)
|
||||
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
size_t FileSize = ftell(hFile);
|
||||
if(FileSize < 64)
|
||||
Shutdown_M("Not a valid Windows PE file");
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
Data = (uint8_t*) malloc(FileSize);
|
||||
if(!Data)
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
if(fread(Data, 1, FileSize, hFile) != FileSize)
|
||||
Shutdown_M("Failed to read input file");
|
||||
|
||||
fclose(hFile);
|
||||
|
||||
brc.start = brc.position = 0;
|
||||
brc.end = FileSize;
|
||||
}
|
||||
~PEFile(){
|
||||
if(hFile)
|
||||
fclose(hFile);
|
||||
free(Data);
|
||||
}
|
||||
|
||||
inline bool seek(size_t pos, int offset = 0){
|
||||
return brc.seek(pos + offset);
|
||||
}
|
||||
|
||||
inline bool skip(size_t pos = 1, int offset = 0){
|
||||
return brc.skip(pos + offset);
|
||||
}
|
||||
int nextchar(){
|
||||
if(!brc.skip())
|
||||
return EOF;
|
||||
return Data[brc.position-1];
|
||||
}
|
||||
void lookat(Segment& segment){
|
||||
brc.start = brc.position = segment.offset;
|
||||
brc.end = segment.offset + segment.size;
|
||||
}
|
||||
|
||||
uint32_t read32(){
|
||||
return brc.skip(4) ? read_uint32(Data+brc.position-4) : -1;
|
||||
}
|
||||
uint16_t read16(){
|
||||
return brc.skip(2) ? read_uint16(Data+brc.position-2) : -1;
|
||||
}
|
||||
size_t strlen(){
|
||||
size_t i = (size_t)-1;
|
||||
int byte;
|
||||
do {
|
||||
byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return -1;
|
||||
i++;
|
||||
} while(byte);
|
||||
skip(-(int)i-1); //Seek back
|
||||
return i;
|
||||
}
|
||||
bool strcpy(char * dest){
|
||||
int i = 0;
|
||||
do {
|
||||
int byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return false;
|
||||
*dest = (char) byte;
|
||||
i--;
|
||||
} while(*dest++);
|
||||
skip(i); //Seek back
|
||||
return true;
|
||||
}
|
||||
int strcmp(const char * data){
|
||||
int i = 0;
|
||||
int byte;
|
||||
do {
|
||||
byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return -1;
|
||||
i--;
|
||||
} while(*data++ && (char)byte == *(data-1));
|
||||
skip(i); //Seek back
|
||||
return byte - *(data-1);
|
||||
}
|
||||
enum { Parse_QuestionMark = 1};
|
||||
bool memfind(const char * data, size_t size, int MemParse = 0){
|
||||
size_t i = 0;
|
||||
do {
|
||||
int byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return false;
|
||||
else if((char)byte != data[i] && (!MemParse || data[i] != '?')){
|
||||
skip(-(int)i);
|
||||
i = 0;
|
||||
} else i++;
|
||||
} while(i<size);
|
||||
skip(-(int)i); //Seek back
|
||||
return true;
|
||||
}
|
||||
|
||||
bool find32(uint32_t address){
|
||||
char buffer[4];
|
||||
write_uint32(buffer, address);
|
||||
return memfind(buffer, 4);
|
||||
}
|
||||
|
||||
bool GenericFill(uint8_t *ptr, size_t count){
|
||||
const size_t padding = offsetof(PaddingTest,B)-offsetof(PaddingTest,A);
|
||||
count -= padding;
|
||||
if(count > brc.end - brc.position)
|
||||
return false;
|
||||
|
||||
uint32_t *field = reinterpret_cast<uint32_t*>(ptr);
|
||||
*field = brc.position; //The Address field always comes first
|
||||
|
||||
do {
|
||||
ptr += padding; count -= padding;
|
||||
field = reinterpret_cast<uint32_t*>(ptr);
|
||||
*field = read32();
|
||||
} while(count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool Fill(T& context) {
|
||||
return GenericFill(reinterpret_cast<uint8_t*>(&context.Fields), sizeof(context.Fields));
|
||||
}
|
||||
};
|
||||
|
||||
PEFile * PEFile::ptr;
|
||||
|
||||
static void Shutdown_M(const char * Message){
|
||||
fprintf(stderr, "rtti-reader: error: %s.\n", Message);
|
||||
if(PEFile::ptr)
|
||||
PEFile::ptr->~PEFile();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned i;
|
||||
const char * InFile, * BaseName;
|
||||
|
||||
if(argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: rtti-reader infile\n"
|
||||
"Extract class information from an EXE or DLL using MSVC RTTI.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"rtti-reader is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
InFile = argv[1];
|
||||
|
||||
int slash;
|
||||
for(i=0, slash=-1; InFile[i]; i++)
|
||||
if(InFile[i] == '/' || InFile[i] == '\\') slash = i;
|
||||
BaseName = InFile + slash + 1;
|
||||
|
||||
PEFile DLL(InFile);
|
||||
if(DLL.read16() != 0x5A4D) //"MZ"
|
||||
Shutdown_M("Not a valid Windows PE file");
|
||||
|
||||
DLL.seek(60);
|
||||
DLL.seek(DLL.read32(), 6); unsigned SegmentCount = DLL.read16();
|
||||
DLL.skip(12); unsigned OptionalHeaderSize = DLL.read16();
|
||||
DLL.skip(30); unsigned ImageBase = DLL.read32();
|
||||
DLL.skip(OptionalHeaderSize, -32);
|
||||
|
||||
for(i=0; i<SegmentCount; i++){
|
||||
if(!DLL.strcmp(".rdata")){
|
||||
DLL.skip(16); DLL.rdata.size = DLL.read32();
|
||||
DLL.rdata.offset = DLL.read32();
|
||||
DLL.skip(16);
|
||||
} else if(!DLL.strcmp(".data")){
|
||||
DLL.skip(16); DLL.data.size = DLL.read32();
|
||||
DLL.data.offset = DLL.read32();
|
||||
DLL.skip(16);
|
||||
} else DLL.skip(40);
|
||||
}
|
||||
if(DLL.rdata.size == 0)
|
||||
Shutdown_M("Missing .rdata segment");
|
||||
else if(DLL.data.size == 0)
|
||||
Shutdown_M("Missing .data segment");
|
||||
else if(DLL.rdata.size > UINT_MAX-DLL.rdata.offset || DLL.rdata.size+DLL.rdata.offset > DLL.brc.end)
|
||||
Shutdown_M(".rdata segment is invalid");
|
||||
else if(DLL.data.size > UINT_MAX-DLL.data.offset || DLL.data.size+DLL.data.offset > DLL.brc.end)
|
||||
Shutdown_M(".data segment is invalid");
|
||||
|
||||
printf("\n****\n** [ 1 of 2] RTTI Report for %s\n****\n", BaseName);
|
||||
|
||||
RTTIVector<RTTIClass> RCL;
|
||||
RCL.init();
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
unsigned TotalClassCount = 0;
|
||||
while(DLL.skip(8) && DLL.memfind(".?AV", 4, PEFile::Parse_QuestionMark)){
|
||||
TotalClassCount++;
|
||||
size_t length = DLL.strlen();
|
||||
if(length == (unsigned)-1)
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
size_t TDAddress = DLL.brc.position + ImageBase - 8, datapos = DLL.brc.position + length + 1;
|
||||
DLL.lookat(DLL.rdata);
|
||||
|
||||
RTTIClass * RCPointer = NULL;
|
||||
|
||||
for(size_t rdatapos = DLL.brc.position + 12;
|
||||
DLL.seek(rdatapos) && DLL.find32(TDAddress); rdatapos += 4, DLL.lookat(DLL.rdata)){
|
||||
//Find all complete object locators that belong to this class
|
||||
rdatapos = DLL.brc.position;
|
||||
if(!DLL.skip(4))
|
||||
continue;
|
||||
size_t CDAddress = DLL.read32() - ImageBase;
|
||||
if(CDAddress < DLL.brc.start || CDAddress > DLL.brc.end-4)
|
||||
continue; //This was a base class descriptor
|
||||
|
||||
//Add this COL to our respective RTTIClass
|
||||
bool newclass = false;
|
||||
if(RCPointer == NULL){
|
||||
//This is a new class; add it to the RCL
|
||||
newclass = true;
|
||||
RTTIClass& RC = RCL.add();
|
||||
RCPointer = &RC;
|
||||
RC.init();
|
||||
}
|
||||
RTTIClass& RC = *RCPointer;
|
||||
|
||||
RTTICompleteObjectLocator& COL = RC.COLL.add();
|
||||
|
||||
DLL.seek(rdatapos,-12);
|
||||
size_t COLAddress = DLL.brc.position + ImageBase;
|
||||
if(!DLL.Fill(COL))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
DLL.lookat(DLL.rdata);
|
||||
COL.VTableAddress = (DLL.find32(COLAddress)) ? DLL.brc.position + ImageBase + 4 : (uint32_t)-1;
|
||||
|
||||
if(newclass){
|
||||
if(!DLL.seek(COL.Fields.ClassDescriptorAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||
if(!DLL.Fill(CHD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
if(!DLL.seek(CHD.Fields.BaseClassListAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
size_t bcdlpos;
|
||||
for(i=0, bcdlpos = DLL.brc.position; i<CHD.Fields.BaseClassCount; i++, bcdlpos+=4){
|
||||
DLL.lookat(DLL.rdata);
|
||||
if(!DLL.seek(bcdlpos))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
uint32_t BCDAddress = DLL.read32();
|
||||
if(!DLL.seek(BCDAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
RTTIBaseClassDescriptor& BCD = CHD.BCDL.add();
|
||||
if(!DLL.Fill(BCD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
if(!DLL.seek(BCD.Fields.TypeDescriptorAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
if(!DLL.Fill(BCD.TD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
length = DLL.strlen();
|
||||
if(length == (unsigned)-1)
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
BCD.TD.Name = (char*) malloc(length+1);
|
||||
BCD.TD.UnmangledName = (char*) malloc(length+1-6);
|
||||
if(!BCD.TD.Name || !BCD.TD.UnmangledName)
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
DLL.strcpy(BCD.TD.Name);
|
||||
for(size_t j=0; j<length-6; j++){
|
||||
char c = BCD.TD.Name[j+4];
|
||||
BCD.TD.UnmangledName[j] = (
|
||||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '_')
|
||||
? c : ' ';
|
||||
}
|
||||
BCD.TD.UnmangledName[length-6] = '\0';
|
||||
|
||||
if(newclass){
|
||||
newclass = false;
|
||||
memcpy(&RC.TD, &BCD.TD, sizeof(RTTITypeDescriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
DLL.seek(datapos);
|
||||
}
|
||||
|
||||
for (i=0; i<RCL.Count; i++){
|
||||
RTTIClass& RC = RCL.Buffer[i];
|
||||
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||
printf("\nClass %s (mangled: %s)\n", RC.TD.UnmangledName, RC.TD.Name);
|
||||
printf(" * Class Hierarchy Descriptor: (Address %08X)\n", CHD.Fields.Address + ImageBase);
|
||||
printf(" * Reserved: %u\n", CHD.Fields.Reserved);
|
||||
printf(" * Attributes: %u\n", CHD.Fields.Attributes);
|
||||
printf(" * Base class count: %u\n", CHD.Fields.BaseClassCount);
|
||||
printf(" * Base class list address: %08X\n", CHD.Fields.BaseClassListAddress);
|
||||
for(uint32_t j=0; j<CHD.Fields.BaseClassCount; j++){
|
||||
RTTIBaseClassDescriptor& BCD = CHD.BCDL.Buffer[j];
|
||||
printf(" * Base class descriptor #%u: (Address %08X)\n", j, BCD.Fields.Address + ImageBase);
|
||||
printf(" * Base class count: %u\n", BCD.Fields.BaseClassCount);
|
||||
printf(" * Member offset: %d\n", BCD.Fields.MemberOffset);
|
||||
printf(" * COL address offset: %d\n", BCD.Fields.COLAddressOffset);
|
||||
printf(" * v-table offset: %d\n", BCD.Fields.VTableOffset);
|
||||
printf(" * Attributes: %u\n", BCD.Fields.Attributes);
|
||||
printf(" * Type descriptor: (Address %08X)\n", BCD.Fields.TypeDescriptorAddress);
|
||||
printf(" * v-table address: %08X\n", BCD.TD.Fields.VTableAddress);
|
||||
printf(" * Reserved: %u\n", BCD.TD.Fields.Reserved);
|
||||
printf(" * Name: %s (mangled: %s)\n", BCD.TD.UnmangledName, BCD.TD.Name);
|
||||
}
|
||||
for(uint32_t j=0; j<RC.COLL.Count; j++){
|
||||
RTTICompleteObjectLocator& COL = RC.COLL.Buffer[j];
|
||||
printf(" * Complete object locator #%u: (Address %08X)\n", j, COL.Fields.Address + ImageBase);
|
||||
printf(" * Reserved: %u\n", COL.Fields.Reserved);
|
||||
printf(" * Offset: %d\n", COL.Fields.Offset);
|
||||
printf(" * CD Offset: %d\n", COL.Fields.CDOffset);
|
||||
printf(" * Type descriptor address: %08X\n", COL.Fields.TypeDescriptorAddress);
|
||||
printf(" * Class descriptor address: %08X\n", COL.Fields.ClassDescriptorAddress);
|
||||
printf(" * v-table address: %08X\n", COL.VTableAddress);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n****\n** [ 2 of 2 ] Class Hierarchy for %s\n****\n", BaseName);
|
||||
|
||||
qsort(RCL.Buffer, RCL.Count, sizeof(RTTIClass), RTTIClass::Compare);
|
||||
|
||||
for(i=0; i<RCL.Count; i++){
|
||||
RTTIClass& RC = RCL.Buffer[i];
|
||||
printf("\nclass %s", RC.TD.UnmangledName);
|
||||
if(RC.CHD.BCDL.Count > 1){
|
||||
//The first BCD always refers to the class itself, e.g. class A "depends on class A".
|
||||
printf(" : %s", RC.CHD.BCDL.Buffer[1].TD.UnmangledName);
|
||||
for(uint32_t j=2; j<RC.CHD.BCDL.Count; j++)
|
||||
printf(", %s", RC.CHD.BCDL.Buffer[j].TD.UnmangledName);
|
||||
}
|
||||
printf(";");
|
||||
}
|
||||
|
||||
printf("\n\nCompleted RTTI report.\nDependencies provided for %u of %u classes.\n", (unsigned)RCL.Count, TotalClassCount);
|
||||
|
||||
return 0;
|
||||
}
|
13
library/tools/tsoscan/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(tsoscan)
|
||||
|
||||
set(TSOSCAN_SOURCES
|
||||
tsoscan.c
|
||||
cmd.c
|
||||
stats.c
|
||||
)
|
||||
|
||||
include_directories(${FILEHANDLER_INCLUDE})
|
||||
|
||||
add_executable(tsoscan ${TSOSCAN_SOURCES})
|
||||
target_link_libraries(tsoscan iff_static)
|
67
library/tools/tsoscan/cmd.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
tsoscan - IFF statistical webpage generator
|
||||
cmd.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "tsoscan.h"
|
||||
|
||||
CommandLineArgs* cmd_parse_args(int argc, char *argv[]){
|
||||
CommandLineArgs *CmdArgs = calloc(1, sizeof(CommandLineArgs));
|
||||
int i, InDirIndex = 0;
|
||||
|
||||
if(CmdArgs == NULL) return 0;
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
if(!strcmp(argv[i], "-o"))
|
||||
i++;
|
||||
else if(strcmp(argv[i], "-f") != 0)
|
||||
CmdArgs->InDirCount++;
|
||||
}
|
||||
if(CmdArgs->InDirCount > 0){
|
||||
CmdArgs->InDirs = calloc(CmdArgs->InDirCount, sizeof(char*));
|
||||
if(CmdArgs->InDirs == NULL) return 0;
|
||||
}
|
||||
|
||||
for(i=1; i<argc; i++){
|
||||
if(!strcmp(argv[i], "-f")){
|
||||
CmdArgs->ForceWrite = 1;
|
||||
}else if(!strcmp(argv[i], "-o")){
|
||||
if(i == argc-1 || CmdArgs->OutFile != NULL)
|
||||
return NULL;
|
||||
CmdArgs->OutFile = argv[++i];
|
||||
}else{
|
||||
CmdArgs->InDirs[InDirIndex] = argv[i];
|
||||
InDirIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return CmdArgs;
|
||||
}
|
||||
|
||||
void cmd_delete(CommandLineArgs *args){
|
||||
unsigned i;
|
||||
|
||||
if(args == NULL) return;
|
||||
if(args->InDirs != NULL){
|
||||
for(i=0; i<args->InDirCount; i++)
|
||||
free(args->InDirs[i]);
|
||||
free(args->InDirs);
|
||||
}
|
||||
free(args->OutFile);
|
||||
free(args);
|
||||
}
|
108
library/tools/tsoscan/stats.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
tsoscan - IFF statistical webpage generator
|
||||
stats.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iff/iff.h>
|
||||
#include "tsoscan.h"
|
||||
|
||||
int stats_create(IFFStats *stats){
|
||||
stats->AverageChunkCount = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stats_version_increment(IFFStats *stats, char *type, unsigned version){
|
||||
ChunkStats *chunk = NULL;
|
||||
VersionInfo *verinfo = NULL;
|
||||
unsigned i;
|
||||
|
||||
if(stats == NULL) return 0;
|
||||
if(type == NULL) return 0;
|
||||
|
||||
for(i=0; i<stats->ChunkTypeCount; i++){
|
||||
if(!strcmp(stats->ChunkTypes[i].Type, type)){
|
||||
chunk = stats->ChunkTypes+i;
|
||||
if(chunk == NULL) return 0;
|
||||
}
|
||||
}
|
||||
if(chunk == NULL){
|
||||
stats->ChunkTypes = realloc(stats->ChunkTypes, ++(stats->ChunkTypeCount)*sizeof(ChunkStats));
|
||||
if(stats->ChunkTypes == NULL) return 0;
|
||||
chunk = stats->ChunkTypes + stats->ChunkTypeCount - 1;
|
||||
memset(chunk, 0, sizeof(ChunkStats));
|
||||
strcpy(chunk->Type, type);
|
||||
}
|
||||
chunk->ChunkCount++;
|
||||
|
||||
for(i=0; i<chunk->VersionCount; i++){
|
||||
if(chunk->Versions[i].Version == version){
|
||||
verinfo = chunk->Versions+i;
|
||||
if(verinfo == NULL) return 0;
|
||||
}
|
||||
}
|
||||
if(verinfo == NULL){
|
||||
chunk->Versions = realloc(chunk->Versions, ++(chunk->VersionCount)*sizeof(VersionInfo));
|
||||
if(chunk->Versions == NULL) return 0;
|
||||
verinfo = chunk->Versions + chunk->VersionCount - 1;
|
||||
memset(verinfo, 0, sizeof(VersionInfo));
|
||||
verinfo->Version = version;
|
||||
}
|
||||
verinfo->Count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned stats_get_version(char *type, uint8_t *data){
|
||||
/* I could've used iff_parse_chunk instead to determine chunk versions, but this
|
||||
would be unnecessarily slow and would require all chunk parsers to be written,
|
||||
defeating the purpose of this tool. */
|
||||
|
||||
if(!strcmp(type, "STR#") || !strcmp(type, "CTSS") || !strcmp(type, "FAMs") ||
|
||||
!strcmp(type, "TTAs") || !strcmp(type, "CST") || !strcmp(type, "BHAV") ||
|
||||
!strcmp(type, "DGRP") || !strcmp(type, "POSI"))
|
||||
return read_uint16le(data);
|
||||
|
||||
if(!strcmp(type, "FCNS") || !strcmp(type, "OBJf") || !strcmp(type, "Optn") ||
|
||||
!strcmp(type, "Rcon") || !strcmp(type, "TPRP") || !strcmp(type, "SLOT") ||
|
||||
!strcmp(type, "TRCN") || !strcmp(type, "rsmp"))
|
||||
return read_uint32le(data+4);
|
||||
|
||||
if(!strcmp(type, "OBJD") || !strcmp(type, "PALT") || !strcmp(type, "SPR2"))
|
||||
return read_uint32le(data);
|
||||
|
||||
if(!strcmp(type, "TTAB"))
|
||||
return read_uint16le(data+2);
|
||||
|
||||
if(!strcmp(type, "SPR#")){
|
||||
if(data[0] == 0) return read_uint32be(data);
|
||||
else return read_uint32le(data);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void stats_delete(IFFStats *stats){
|
||||
unsigned i;
|
||||
|
||||
if(stats == NULL) return;
|
||||
if(stats->ChunkTypes != NULL){
|
||||
for(i=0; i<stats->ChunkTypeCount; i++)
|
||||
free(stats->ChunkTypes[i].Versions);
|
||||
free(stats->ChunkTypes);
|
||||
}
|
||||
}
|
328
library/tools/tsoscan/tsoscan.c
Normal file
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
tsoscan - IFF statistical webpage generator
|
||||
tsoscan.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
|
||||
Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <iff/iff.h>
|
||||
#include "tsoscan.h"
|
||||
|
||||
static void print_usage(){
|
||||
printf("Usage: tsoscan [-f] [-o outfile] indir1 [indir2 [...]]\n"
|
||||
"Generate a statistical HTML page based on a number of IFF files.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
"If outfile is unspecified, the output HTML page will be written to stats.html.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"tsoscan is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
CommandLineArgs *CmdArgs;
|
||||
unsigned i, version, FileCount = 0;
|
||||
char **Files = NULL;
|
||||
IFFStats Stats;
|
||||
FILE *OutFile;
|
||||
|
||||
if(!stats_create(&Stats)){
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
CmdArgs = cmd_parse_args(argc, argv);
|
||||
if(CmdArgs == NULL || CmdArgs->InDirCount == 0){
|
||||
print_usage();
|
||||
return -1;
|
||||
}
|
||||
if(CmdArgs->OutFile == NULL){
|
||||
CmdArgs->OutFile = "stats.html";
|
||||
}
|
||||
|
||||
/****
|
||||
** List selected input directories
|
||||
*/
|
||||
|
||||
for(i=0; i<CmdArgs->InDirCount; i++){
|
||||
DIR *dir = opendir(CmdArgs->InDirs[i]);
|
||||
struct dirent *entry;
|
||||
unsigned DirStartIndex;
|
||||
|
||||
if(dir == NULL){
|
||||
fprintf(stderr, "%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
DirStartIndex = FileCount;
|
||||
while((entry = readdir(dir)) != NULL){
|
||||
if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
|
||||
FileCount++;
|
||||
}
|
||||
rewinddir(dir);
|
||||
Files = realloc(Files, FileCount*sizeof(char**));
|
||||
if(Files == NULL){
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(; DirStartIndex<FileCount;){
|
||||
entry = readdir(dir);
|
||||
if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")){
|
||||
int dirlen = strlen(CmdArgs->InDirs[i]);
|
||||
int pathlen = strlen(entry->d_name);
|
||||
Files[DirStartIndex] = malloc(dirlen+pathlen+2);
|
||||
if(Files[DirStartIndex] == NULL){
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(Files[DirStartIndex], CmdArgs->InDirs[i], dirlen);
|
||||
Files[DirStartIndex][dirlen] = PATH_SEP;
|
||||
memcpy(Files[DirStartIndex]+dirlen+1, entry->d_name, pathlen);
|
||||
Files[DirStartIndex][dirlen+pathlen+1] = '\0';
|
||||
|
||||
DirStartIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/****
|
||||
** Load and parse IFF files
|
||||
*/
|
||||
|
||||
for(i=0; i<FileCount; i++){
|
||||
FILE *file;
|
||||
size_t FileSize;
|
||||
uint8_t *data;
|
||||
IFFFile iff;
|
||||
IFFChunk *ChunkData;
|
||||
unsigned ChunkIndex;
|
||||
|
||||
printf("(%d/%d)\r", i+1, FileCount);
|
||||
|
||||
file = fopen(Files[i], "rb");
|
||||
if(file == NULL){
|
||||
fprintf(stderr, "%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
continue;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
FileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
data = malloc(FileSize);
|
||||
if(data == NULL){
|
||||
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if(fread(data, 1, FileSize, file) != FileSize){
|
||||
fprintf(stderr, "%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
free(data);
|
||||
fclose(file);
|
||||
continue;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if(!iff_create(&iff)){
|
||||
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(&iff, data, FileSize) || !iff_enumerate_chunks(&iff, data+64, FileSize-64)){
|
||||
/* Skip non-IFF files silently */
|
||||
free(data);
|
||||
continue;
|
||||
}
|
||||
free(data);
|
||||
|
||||
Stats.FileCount++;
|
||||
if(Stats.AverageChunkCount == -1){
|
||||
Stats.AverageChunkCount = iff.ChunkCount;
|
||||
}else{
|
||||
Stats.AverageChunkCount += iff.ChunkCount;
|
||||
Stats.AverageChunkCount /= 2;
|
||||
}
|
||||
|
||||
for(ChunkIndex = 0, ChunkData = iff.Chunks; ChunkIndex < iff.ChunkCount; ChunkIndex++, ChunkData++){
|
||||
unsigned version = stats_get_version(ChunkData->Type, ChunkData->Data);
|
||||
if(!stats_version_increment(&Stats, ChunkData->Type, version)){
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
iff_delete(&iff);
|
||||
}
|
||||
|
||||
/****
|
||||
** Write output file
|
||||
*/
|
||||
|
||||
if(!CmdArgs->ForceWrite){
|
||||
OutFile = fopen(CmdArgs->OutFile, "rb");
|
||||
if(OutFile != NULL){
|
||||
char c;
|
||||
fclose(OutFile);
|
||||
printf("File \"%s\" exists. Continue anyway? (y/n) ", CmdArgs->OutFile);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y')
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
OutFile = fopen(CmdArgs->OutFile, "wb");
|
||||
if(OutFile == NULL){
|
||||
fprintf(stderr, "%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(OutFile,
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
|
||||
fprintf(OutFile, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\">\n");
|
||||
fprintf(OutFile, "<head>\n");
|
||||
fprintf(OutFile, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n");
|
||||
fprintf(OutFile, "<meta http-equiv=\"Content-Style-Type\" content=\"text/css; charset=utf-8\" />\n");
|
||||
fprintf(OutFile, "<meta http-equiv=\"Content-Language\" content=\"en\" />\n");
|
||||
fprintf(OutFile, "<meta name=\"description\" content=\"tsostats\" />\n");
|
||||
fprintf(OutFile, "<meta name=\"generator\" content=\"IFF Chunk Statistics (tsostats)\" />\n");
|
||||
fprintf(OutFile, "<title>IFF Chunk Statistics (tsostats)</title>\n");
|
||||
fprintf(OutFile, "<style type=\"text/css\" media=\"all\">\n");
|
||||
fprintf(OutFile, "html, body {\n");
|
||||
fprintf(OutFile, " background: #fff;\n");
|
||||
fprintf(OutFile, " color: #000;\n");
|
||||
fprintf(OutFile, " font-family: sans-serif;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "a:link, a:visited, a:hover, a:active { color: #00f; }\n");
|
||||
fprintf(OutFile, "a:link, a:visited { text-decoration: none; }\n");
|
||||
fprintf(OutFile, "a:hover, a:active { text-decoration: underline; }\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "#attributes {\n");
|
||||
fprintf(OutFile, " border-left: 2px solid #888; padding-left: 4px; margin-bottom: 1em;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "#toc {\n");
|
||||
fprintf(OutFile, " display: table-cell;\n");
|
||||
fprintf(OutFile, " margin-top: 1em;\n");
|
||||
fprintf(OutFile, " background: #eee; border: 1px solid #bbb;\n");
|
||||
fprintf(OutFile, " padding: .25em;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "#toc div {\n");
|
||||
fprintf(OutFile, " border-bottom: 1px solid #aaa;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "#toc ul {\n");
|
||||
fprintf(OutFile, " list-style-type: none;\n");
|
||||
fprintf(OutFile, " padding: 0;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "ul ul {\n");
|
||||
fprintf(OutFile, " padding: 2em;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "h2 {\n");
|
||||
fprintf(OutFile, " border-bottom: 1px solid #888;\n");
|
||||
fprintf(OutFile, " margin: 2em 0 0.25em 0;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "h2 a {\n");
|
||||
fprintf(OutFile, " font-size: 9pt;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "table {\n");
|
||||
fprintf(OutFile, " border: 1px #aaa solid;\n");
|
||||
fprintf(OutFile, " border-collapse: collapse;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "th, td {\n");
|
||||
fprintf(OutFile, " border: 1px #aaa solid;\n");
|
||||
fprintf(OutFile, " padding: 0.2em;\n");
|
||||
fprintf(OutFile, " white-space: pre-wrap;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, ".center {\n");
|
||||
fprintf(OutFile, " margin: auto auto;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "\n");
|
||||
fprintf(OutFile, "#footer {\n");
|
||||
fprintf(OutFile, " margin-top: 2em;\n");
|
||||
fprintf(OutFile, " padding-bottom: 0.5em;\n");
|
||||
fprintf(OutFile, " text-align: center;\n");
|
||||
fprintf(OutFile, "}\n");
|
||||
fprintf(OutFile, "</style>\n");
|
||||
fprintf(OutFile, "</head>\n");
|
||||
fprintf(OutFile, "<body>\n");
|
||||
fprintf(OutFile, "<h1>IFF Chunk Statistics (tsostats)</h1>\n");
|
||||
fprintf(OutFile, "<div id=\"attributes\">\n");
|
||||
fprintf(OutFile, "<table>\n");
|
||||
fprintf(OutFile, "<tr><td>Number of IFF files:</td><td>%u</td></tr>\n", Stats.FileCount);
|
||||
fprintf(OutFile, "<tr><td>Average chunk count:</td><td>%.1f</td></tr>\n", Stats.AverageChunkCount);
|
||||
fprintf(OutFile, "</table>\n");
|
||||
fprintf(OutFile, "</div>\n");
|
||||
|
||||
fprintf(OutFile, "<div id=\"toc\"><div><b>Contents</b> – %u chunk types</div>\n", Stats.ChunkTypeCount);
|
||||
fprintf(OutFile, "<ul>\n");
|
||||
for(i=0; i<Stats.ChunkTypeCount; i++)
|
||||
fprintf(OutFile, "<li><a href=\"#type%u\">%u %s</a></li>\n", i, i+1, Stats.ChunkTypes[i].Type);
|
||||
fprintf(OutFile, "</ul>\n");
|
||||
fprintf(OutFile, "</div>\n");
|
||||
fprintf(OutFile, "\n");
|
||||
|
||||
for(i=0; i<Stats.ChunkTypeCount; i++){
|
||||
ChunkStats *chunk = Stats.ChunkTypes+i;
|
||||
|
||||
fprintf(OutFile, "<h2 id=\"type%u\">%u %s <a href=\"#type%u\">(Jump)</a></h2>\n", i, i+1, Stats.ChunkTypes[i].Type, i);
|
||||
fprintf(OutFile, "<div>\n");
|
||||
|
||||
fprintf(OutFile, "<table>\n");
|
||||
fprintf(OutFile, "<tr><td>Number of occurrences:</td><td>%u</td></tr>\n", chunk->ChunkCount);
|
||||
if(chunk->VersionCount == 1 && chunk->Versions[0].Version == (unsigned)-1)
|
||||
fprintf(OutFile, "<tr><td>Number of versions:</td><td>N/A</td></tr>\n");
|
||||
else
|
||||
fprintf(OutFile, "<tr><td>Number of versions:</td><td>%u</td></tr>\n", chunk->VersionCount);
|
||||
fprintf(OutFile, "</table>\n");
|
||||
|
||||
if(chunk->VersionCount > 1 ||
|
||||
(chunk->VersionCount == 1 && chunk->Versions[0].Version != (unsigned)-1)){
|
||||
fprintf(OutFile, "<table class=\"center\">\n");
|
||||
fprintf(OutFile, "<tr><th></th><th>Version</th><th>Count</th></tr>\n");
|
||||
for(version=0; version<chunk->VersionCount; version++){
|
||||
VersionInfo *verinfo = chunk->Versions+version;
|
||||
float percentage = (float)verinfo->Count / chunk->ChunkCount * 100;
|
||||
|
||||
fprintf(OutFile, "<tr><td>%u</td><td>%u (<tt>0x%x</tt>)</td><td>%u (%.1f%%)</td></tr>\n",
|
||||
version+1, verinfo->Version, verinfo->Version, verinfo->Count, percentage);
|
||||
}
|
||||
fprintf(OutFile, "</table>\n");
|
||||
}
|
||||
|
||||
fprintf(OutFile, "</div>\n\n");
|
||||
}
|
||||
|
||||
fprintf(OutFile,
|
||||
"<div id=\"footer\">This page was generated by the use of <a href=\"http://www.niotso.org/\">tsostats</a>.</div>\n");
|
||||
fprintf(OutFile, "</body>\n");
|
||||
fprintf(OutFile, "</html>");
|
||||
fclose(OutFile);
|
||||
|
||||
printf("Generated statistics based on %u IFF files.\n", Stats.FileCount);
|
||||
cmd_delete(CmdArgs);
|
||||
stats_delete(&Stats);
|
||||
return 0;
|
||||
}
|
65
library/tools/tsoscan/tsoscan.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
tsoscan - IFF statistical webpage generator
|
||||
tsoscan.h - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define TSOSCAN_WARNING "tsoscan: warning: "
|
||||
#define TSOSCAN_ERROR "tsoscan: error: "
|
||||
#ifdef _WIN32
|
||||
#define PATH_SEP '\\'
|
||||
#else
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
typedef struct CommandLineArgs_s
|
||||
{
|
||||
int ForceWrite;
|
||||
char * OutFile;
|
||||
unsigned InDirCount;
|
||||
char ** InDirs;
|
||||
} CommandLineArgs;
|
||||
|
||||
typedef struct VersionInfo_s
|
||||
{
|
||||
unsigned Version;
|
||||
unsigned Count;
|
||||
} VersionInfo;
|
||||
|
||||
typedef struct ChunkStats_s
|
||||
{
|
||||
char Type[5];
|
||||
unsigned ChunkCount;
|
||||
unsigned VersionCount;
|
||||
VersionInfo * Versions;
|
||||
} ChunkStats;
|
||||
|
||||
typedef struct IFFStats_s
|
||||
{
|
||||
unsigned FileCount;
|
||||
float AverageChunkCount;
|
||||
unsigned ChunkTypeCount;
|
||||
ChunkStats * ChunkTypes;
|
||||
} IFFStats;
|
||||
|
||||
CommandLineArgs* cmd_parse_args(int argc, char *argv[]);
|
||||
void cmd_delete(CommandLineArgs *args);
|
||||
|
||||
int stats_create(IFFStats *stats);
|
||||
int stats_version_increment(IFFStats *stats, char *type, unsigned version);
|
||||
unsigned stats_get_version(char *type, uint8_t *data);
|
||||
void stats_delete(IFFStats *stats);
|
11
library/tools/zbuffer/Instructions.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
Add these files:
|
||||
|
||||
* Chair-Liv-Deco_large_front_a.png
|
||||
* Chair-Liv-Deco_large_front_p.png
|
||||
* Chair-Liv-Deco_large_front_z.png
|
||||
* tower_large_ne_a.png
|
||||
* tower_large_ne_p.png
|
||||
* tower_large_ne_z.png
|
||||
|
||||
Then open index.html in a web browser which supports the HTML5 canvas,
|
||||
and use the arrow keys.
|
BIN
library/tools/zbuffer/background.png
Normal file
After Width: | Height: | Size: 412 B |
152
library/tools/zbuffer/index.html
Normal file
|
@ -0,0 +1,152 @@
|
|||
<script>
|
||||
|
||||
window.onload = init;
|
||||
|
||||
function LoadSpriteset(names) {
|
||||
images = new Array(names.length);
|
||||
imagesloaded = 0;
|
||||
imagecount = 1 + names.length * 3;
|
||||
ext = ['a', 'p', 'z'];
|
||||
for (i = 0; i < names.length; i++) {
|
||||
images[i] = new Array(3);
|
||||
for (j = 0; j < 3; j++) {
|
||||
img = new Image();
|
||||
img.idi = i, img.idj = j;
|
||||
img.src = names[i] + '_' + ext[j] + ".png";
|
||||
img.onload = function() {
|
||||
context.drawImage(this, 0, 0);
|
||||
images[this.idi][this.idj] = context.getImageData(0, 0, 136, 384);
|
||||
delete this;
|
||||
if (++imagesloaded == imagecount) {
|
||||
redraw = true;
|
||||
setInterval(update, 16);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// capture keys
|
||||
left = 0;
|
||||
right = 0;
|
||||
up = 0;
|
||||
down = 0;
|
||||
|
||||
window.onkeydown = function(evt) {
|
||||
if (evt.keyCode == 37) left = 1;
|
||||
if (evt.keyCode == 38) up = 1;
|
||||
if (evt.keyCode == 39) right = 1;
|
||||
if (evt.keyCode == 40) down = 1;
|
||||
};
|
||||
|
||||
window.onkeyup = function(evt) {
|
||||
if (evt.keyCode == 37) left = 0;
|
||||
if (evt.keyCode == 38) up = 0;
|
||||
if (evt.keyCode == 39) right = 0;
|
||||
if (evt.keyCode == 40) down = 0;
|
||||
};
|
||||
// end capture keys
|
||||
|
||||
// The game does not use true isometric projection because each tile is 128x64 (close), 64x32 (medium), or 32x16 (far)
|
||||
// which, when tilex or tiley is the hypotenuse, does not form a 30-60-90 triangle.
|
||||
// It's actually arctan(1/2)-arctan(2/1)-90. The image is compressed vertically a bit to allow for power-of-2 texture sizes.
|
||||
tilex = 0;
|
||||
tiley = 0;
|
||||
sin60 = 2.0/Math.sqrt(5); // sin(arctan(2)) or cos(arctan(1/2))
|
||||
sin30 = 1.0/Math.sqrt(5); // sin(arctan(1/2)) or cos(arctan(2))
|
||||
sqrt5120 = 32*Math.sqrt(5);
|
||||
|
||||
debug = document.getElementById('debug');
|
||||
canvas = document.getElementById('draw');
|
||||
context = canvas.getContext('2d');
|
||||
|
||||
background = new Image();
|
||||
background.src = "background.png";
|
||||
background.onload = function() {
|
||||
context.drawImage(this, 0, 0);
|
||||
delete this;
|
||||
background = context.getImageData(0, 0, 136, 384);
|
||||
if (++imagesloaded == imagecount) {
|
||||
redraw = true;
|
||||
setInterval(update, 16);
|
||||
}
|
||||
}
|
||||
LoadSpriteset(["Chair-Liv-Deco_large_front", "tower_large_ne"]);
|
||||
|
||||
render = context.createImageData(136, 384);
|
||||
}
|
||||
|
||||
function Blend(sourceid, soffset)
|
||||
{
|
||||
sa = images[sourceid][0].data[soffset+0] / 255.0;
|
||||
if (sa == 0) return;
|
||||
sr = images[sourceid][1].data[soffset+0];
|
||||
sg = images[sourceid][1].data[soffset+1];
|
||||
sb = images[sourceid][1].data[soffset+2];
|
||||
if (sa == 255) {
|
||||
render.data[dest+0] = sr;
|
||||
render.data[dest+1] = sr;
|
||||
render.data[dest+2] = sr;
|
||||
return;
|
||||
}
|
||||
|
||||
dr = render.data[dest+0];
|
||||
dg = render.data[dest+1];
|
||||
db = render.data[dest+2];
|
||||
da = 1.0 - sa;
|
||||
|
||||
render.data[dest+0] = da * dr + sa * sr;
|
||||
render.data[dest+1] = da * dg + sa * sg;
|
||||
render.data[dest+2] = da * db + sa * sb;
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
if (!left && !right && !up && !down && !redraw) return;
|
||||
redraw = false;
|
||||
|
||||
if (left == 1) tilex -= 1;
|
||||
if (right == 1) tilex += 1;
|
||||
if (up == 1) tiley += 1;
|
||||
if (down == 1) tiley -= 1;
|
||||
|
||||
screenx = Math.round((tilex + tiley)*sin60);
|
||||
screeny = Math.round((tilex - tiley)*sin30);
|
||||
z = screeny*1.5;
|
||||
|
||||
for (y = 0; y < 384; y++) {
|
||||
for (x = 0; x < 136; x++) {
|
||||
dest = (y*136+x)*4;
|
||||
render.data[dest+0] = background.data[dest+0];
|
||||
render.data[dest+1] = background.data[dest+1];
|
||||
render.data[dest+2] = background.data[dest+2];
|
||||
render.data[dest+3] = 255;
|
||||
|
||||
// Shift: read from the data so-many bytes ago. Subtract rather than add.
|
||||
if (y-screeny >= 0 && y-screeny < 384 && x-screenx >= 0 && x-screenx < 136) {
|
||||
source = ((y-screeny)*136 + x-screenx)*4;
|
||||
|
||||
if (images[1][2].data[source] != 255 && images[1][2].data[source] - z < images[0][2].data[dest]) {
|
||||
// Object 2 on top
|
||||
Blend(0, dest);
|
||||
Blend(1, source);
|
||||
} else {
|
||||
// Object 1 on top
|
||||
Blend(1, source);
|
||||
Blend(0, dest);
|
||||
}
|
||||
} else {
|
||||
// Object 1 only
|
||||
Blend(0, dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.putImageData(render, 0, 0);
|
||||
debug.innerHTML = "Tile x: " + tilex/sqrt5120 + "<br />Tile y: " + tiley/sqrt5120 + "<br />Screen x: " + screenx + "<br />Screen y: " + screeny + "<br />z: " + z;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="debug"></div>
|
||||
<canvas width="136" height="384" id="draw" style="border: 1px solid #888"></canvas>
|