forked from 0ad/0ad
Delete obsolete AoE3Ed code
This was SVN commit r10909.
This commit is contained in:
parent
c9cdde256f
commit
e4b2de4bba
@ -249,23 +249,6 @@ extern_lib_defs = {
|
||||
})
|
||||
end,
|
||||
},
|
||||
devil = {
|
||||
compile_settings = function()
|
||||
if os.is("windows") then
|
||||
add_default_include_paths("devil")
|
||||
end
|
||||
end,
|
||||
link_settings = function()
|
||||
-- On Windows, it uses #pragma comment(lib ...) to link the library,
|
||||
-- so we only need to include the library-search-path
|
||||
if os.is("windows") then
|
||||
add_default_lib_paths("devil")
|
||||
end
|
||||
add_default_links({
|
||||
unix_names = { "IL", "ILU" },
|
||||
})
|
||||
end,
|
||||
},
|
||||
enet = {
|
||||
compile_settings = function()
|
||||
if not _OPTIONS["with-system-enet"] then
|
||||
@ -565,23 +548,6 @@ extern_lib_defs = {
|
||||
})
|
||||
end,
|
||||
},
|
||||
xerces = {
|
||||
compile_settings = function()
|
||||
if os.is("windows") then
|
||||
add_default_include_paths("xerces")
|
||||
end
|
||||
end,
|
||||
link_settings = function()
|
||||
if os.is("windows") then
|
||||
add_default_lib_paths("xerces")
|
||||
end
|
||||
add_default_links({
|
||||
win_names = { "xerces-c_2" },
|
||||
unix_names = { "xerces-c" },
|
||||
no_delayload = 1,
|
||||
})
|
||||
end,
|
||||
},
|
||||
zlib = {
|
||||
compile_settings = function()
|
||||
if os.is("windows") then
|
||||
|
@ -1,7 +1,6 @@
|
||||
newoption { trigger = "atlas", description = "Include Atlas scenario editor projects" }
|
||||
newoption { trigger = "collada", description = "Include COLLADA projects (requires FCollada library)" }
|
||||
newoption { trigger = "coverage", description = "Enable code coverage data collection (GCC only)" }
|
||||
newoption { trigger = "aoe3ed", description = "Include AoE3Ed" }
|
||||
newoption { trigger = "icc", description = "Use Intel C++ Compiler (Linux only; should use either \"--cc icc\" or --without-pch too, and then set CXX=icpc before calling make)" }
|
||||
newoption { trigger = "outpath", description = "Location for generated project files" }
|
||||
newoption { trigger = "without-tests", description = "Disable generation of test projects" }
|
||||
@ -730,10 +729,6 @@ function setup_atlas_project(project_name, target_type, rel_source_dirs, rel_inc
|
||||
project_add_contents(source_root, rel_source_dirs, rel_include_dirs, extra_params)
|
||||
project_add_extern_libs(extern_libs, target_type)
|
||||
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
defines { "USE_AOE3ED" }
|
||||
end
|
||||
|
||||
-- Platform Specifics
|
||||
if os.is("windows") then
|
||||
defines { "_UNICODE" }
|
||||
@ -812,12 +807,6 @@ function setup_atlas_projects()
|
||||
"AtlasObject",
|
||||
"AtlasScript",
|
||||
}
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
table.insert(atlas_src, "ArchiveViewer")
|
||||
table.insert(atlas_src, "FileConverter")
|
||||
table.insert(atlas_extra_links, "DatafileIO")
|
||||
table.insert(atlas_extra_links, "xerces-c")
|
||||
end
|
||||
|
||||
atlas_extern_libs = {
|
||||
"boost",
|
||||
@ -830,9 +819,6 @@ function setup_atlas_projects()
|
||||
"x11",
|
||||
"zlib",
|
||||
}
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
table.insert(atlas_extern_libs, "devil")
|
||||
end
|
||||
|
||||
setup_atlas_project("AtlasUI", "SharedLib", atlas_src,
|
||||
{ -- include
|
||||
@ -847,25 +833,6 @@ function setup_atlas_projects()
|
||||
extra_links = atlas_extra_links,
|
||||
extra_files = { "Misc/atlas.rc" }
|
||||
})
|
||||
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
setup_atlas_project("DatafileIO", "StaticLib",
|
||||
{ -- src
|
||||
".",
|
||||
"BAR",
|
||||
"DDT",
|
||||
"SCN",
|
||||
"Stream",
|
||||
"XMB"
|
||||
},{ -- include
|
||||
},{ -- extern_libs
|
||||
"devil",
|
||||
"xerces",
|
||||
"zlib"
|
||||
},{ -- extra_params
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -899,9 +866,6 @@ function setup_atlas_frontend_project (project_name)
|
||||
project_add_manifest()
|
||||
|
||||
else -- Non-Windows, = Unix
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
links { "DatafileIO" }
|
||||
end
|
||||
links { "AtlasObject" }
|
||||
end
|
||||
|
||||
@ -911,10 +875,6 @@ end
|
||||
|
||||
function setup_atlas_frontends()
|
||||
setup_atlas_frontend_project("ActorEditor")
|
||||
if _OPTIONS["aoe3ed"] then
|
||||
setup_atlas_frontend_project("ArchiveViewer")
|
||||
setup_atlas_frontend_project("FileConverter")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
// Use WinXP-style controls
|
||||
# if _MSC_VER >= 1400 // (can't be bothered to implement this for VC7.1...)
|
||||
# pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"")
|
||||
# endif
|
||||
|
||||
# define ATLASDLLIMPEXP extern "C" __declspec(dllimport)
|
||||
#else
|
||||
# define ATLASDLLIMPEXP extern "C"
|
||||
#endif
|
||||
|
||||
#include "AtlasUI/Misc/DLLInterface.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
#else
|
||||
int main()
|
||||
#endif
|
||||
{
|
||||
Atlas_StartWindow(L"ArchiveViewer");
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\ArchiveViewer.ico"
|
@ -1,43 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
// Use WinXP-style controls
|
||||
# if _MSC_VER >= 1400 // (can't be bothered to implement this for VC7.1...)
|
||||
# pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"")
|
||||
# endif
|
||||
|
||||
# define ATLASDLLIMPEXP extern "C" __declspec(dllimport)
|
||||
#else
|
||||
# define ATLASDLLIMPEXP extern "C"
|
||||
#endif
|
||||
|
||||
#include "AtlasUI/Misc/DLLInterface.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
#else
|
||||
int main()
|
||||
#endif
|
||||
{
|
||||
Atlas_StartWindow(L"FileConverter");
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
IDI_ICON1 ICON "..\\AtlasUI\\Misc\\Graphics\\FileConverter.ico"
|
@ -8,15 +8,6 @@ my @progs = (
|
||||
PROJECT_NAME => "ActorEditor",
|
||||
WINDOW_NAME => "ActorEditor",
|
||||
},
|
||||
{
|
||||
PROJECT_NAME => "FileConverter",
|
||||
WINDOW_NAME => "FileConverter",
|
||||
},
|
||||
{
|
||||
PROJECT_NAME => "ArchiveViewer",
|
||||
WINDOW_NAME => "ArchiveViewer",
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
for my $p (@progs) {
|
||||
|
@ -1,652 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ArchiveViewer.h"
|
||||
|
||||
#include "Misc/Version.h"
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "DatafileIO/BAR/BAR.h"
|
||||
#include "DatafileIO/Stream/Stream.h"
|
||||
#include "DatafileIO/Stream/wx.h"
|
||||
using namespace DatafileIO;
|
||||
|
||||
#include "wx/dnd.h"
|
||||
#include "wx/confbase.h"
|
||||
#include "wx/wfstream.h"
|
||||
#include "wx/tooltip.h"
|
||||
#include "wx/progdlg.h"
|
||||
#include "wx/regex.h"
|
||||
#ifdef __WXMSW__
|
||||
# include "wx/msw/registry.h"
|
||||
#endif
|
||||
|
||||
// Possible TODO: Remove duplication of AtlasWindow code
|
||||
|
||||
enum {
|
||||
ID_ExtractSelected,
|
||||
ID_ExtractAll,
|
||||
ID_EnablePreview,
|
||||
ID_About
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(ArchiveViewer, wxFrame)
|
||||
EVT_MENU(wxID_OPEN, ArchiveViewer::OnOpen)
|
||||
EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, ArchiveViewer::OnMRUFile)
|
||||
EVT_MENU(wxID_EXIT, ArchiveViewer::OnQuit)
|
||||
EVT_MENU(ID_ExtractSelected, ArchiveViewer::OnExtractSelected)
|
||||
EVT_MENU(ID_ExtractAll, ArchiveViewer::OnExtractAll)
|
||||
EVT_MENU(ID_EnablePreview, ArchiveViewer::OnEnablePreview)
|
||||
EVT_MENU(ID_About, ArchiveViewer::OnAbout)
|
||||
EVT_CLOSE(ArchiveViewer::OnClose)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class FilterTextCtrl : public wxTextCtrl
|
||||
{
|
||||
public:
|
||||
FilterTextCtrl(wxWindow* parent, ArchiveViewer* archViewWin, const wxSize& size)
|
||||
: wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, size),
|
||||
m_archViewWin(archViewWin) {}
|
||||
private:
|
||||
void OnChange(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
m_archViewWin->SetFilter(GetValue());
|
||||
}
|
||||
ArchiveViewer* m_archViewWin;
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
BEGIN_EVENT_TABLE(FilterTextCtrl, wxTextCtrl)
|
||||
EVT_TEXT(wxID_ANY, FilterTextCtrl::OnChange)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
class FileListCtrl : public wxListCtrl
|
||||
{
|
||||
public:
|
||||
FileListCtrl(wxWindow* parent, ArchiveViewer* archViewWin)
|
||||
: wxListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT),
|
||||
m_archViewWin(archViewWin) {}
|
||||
void OnSelect(wxListEvent& event)
|
||||
{
|
||||
m_archViewWin->UpdatePreview(event.GetIndex());
|
||||
}
|
||||
private:
|
||||
ArchiveViewer* m_archViewWin;
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
BEGIN_EVENT_TABLE(FileListCtrl, wxListCtrl)
|
||||
EVT_LIST_ITEM_SELECTED(wxID_ANY, FileListCtrl::OnSelect)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Allow drag-and-drop of files onto the window, as a convenient way of opening them
|
||||
//class DropTarget : public wxFileDropTarget
|
||||
//{
|
||||
//public:
|
||||
// DropTarget(ColourTesterImageCtrl* imgctrl)
|
||||
// : m_ImageCtrl(imgctrl)
|
||||
// {}
|
||||
//
|
||||
// bool OnDropFiles(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxArrayString& filenames)
|
||||
// {
|
||||
// if (filenames.GetCount() >= 1)
|
||||
// m_ImageCtrl->SetImageFile(filenames[0]);
|
||||
// return true;
|
||||
// }
|
||||
//private:
|
||||
// ColourTesterImageCtrl* m_ImageCtrl;
|
||||
//};
|
||||
|
||||
|
||||
ArchiveViewer::ArchiveViewer(wxWindow* parent)
|
||||
: wxFrame(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(600, 371))
|
||||
, m_FileHistory(_T("Archive Viewer"))
|
||||
, m_WindowTitle(wxString::Format(_("%s - Archive Viewer"), g_ProgramNameVersion.c_str()))
|
||||
, m_BARStream(NULL), m_BARReader(NULL), m_PreviewEnabled(false)
|
||||
{
|
||||
SetIcon(wxIcon(_T("ICON_ArchiveViewer")));
|
||||
|
||||
wxToolTip::Enable(true);
|
||||
|
||||
wxMenuBar* menuBar = new wxMenuBar;
|
||||
SetMenuBar(menuBar);
|
||||
|
||||
wxMenu *menuFile = new wxMenu;
|
||||
menuBar->Append(menuFile, _("&File"));
|
||||
{
|
||||
menuFile->Append(wxID_OPEN, _("&Open..."));
|
||||
menuFile->AppendSeparator();//-----------
|
||||
menuFile->Append(wxID_EXIT, _("E&xit"));
|
||||
m_FileHistory.UseMenu(menuFile);//-------
|
||||
m_FileHistory.AddFilesToMenu();
|
||||
}
|
||||
|
||||
wxMenu *menuView = new wxMenu;
|
||||
menuBar->Append(menuView, _("&View"));
|
||||
{
|
||||
menuView->AppendCheckItem(ID_EnablePreview, _("&Preview"));
|
||||
}
|
||||
|
||||
wxMenu *menuExtract = new wxMenu;
|
||||
menuBar->Append(menuExtract, _("&Extract"));
|
||||
{
|
||||
menuExtract->Append(ID_ExtractAll, _("&All files..."));
|
||||
menuExtract->Append(ID_ExtractSelected, _("&Selected..."));
|
||||
}
|
||||
|
||||
wxMenu *menuHelp = new wxMenu;
|
||||
menuBar->Append(menuHelp, _("&Help"));
|
||||
{
|
||||
menuHelp->Append(ID_About, _("&About"));
|
||||
}
|
||||
|
||||
|
||||
m_FileHistory.Load(*wxConfigBase::Get());
|
||||
|
||||
|
||||
|
||||
m_Splitter = new SnapSplitterWindow(this, wxSP_NOBORDER | wxSP_3DSASH);
|
||||
|
||||
wxPanel* leftPanel = new wxPanel(m_Splitter);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set up sizers:
|
||||
|
||||
wxBoxSizer* vertSizer = new wxBoxSizer(wxVERTICAL);
|
||||
leftPanel->SetSizer(vertSizer);
|
||||
|
||||
wxBoxSizer* filterSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Add things to sizers:
|
||||
|
||||
m_FileListCtrl = new FileListCtrl(leftPanel, this);
|
||||
m_FileListCtrl->InsertColumn(0, _("Filename"), wxLIST_FORMAT_LEFT, 300);
|
||||
m_FileListCtrl->InsertColumn(1, _("File size (bytes)"), wxLIST_FORMAT_RIGHT, 100);
|
||||
m_FileListCtrl->InsertColumn(2, _("Last modified date"), wxLIST_FORMAT_LEFT, 150);
|
||||
vertSizer->Add(m_FileListCtrl, wxSizerFlags().Expand().Proportion(1).Border(wxALL, 5));
|
||||
|
||||
vertSizer->Add(filterSizer,
|
||||
wxSizerFlags().Expand().Border(wxLEFT|wxRIGHT|wxBOTTOM, 5));
|
||||
|
||||
|
||||
m_PreviewWindow = new FilePreviewer(m_Splitter);
|
||||
m_PreviewWindow->Hide();
|
||||
|
||||
m_Splitter->Initialize(leftPanel);
|
||||
|
||||
filterSizer->Add(new wxStaticText(leftPanel, wxID_ANY, _("&Search for file:")),
|
||||
wxSizerFlags().Centre().Border(wxALL, 5));
|
||||
|
||||
FilterTextCtrl* filterTextCtrl = new FilterTextCtrl(leftPanel, this, wxSize(150, -1));
|
||||
filterTextCtrl->SetToolTip(_("You may use * to match any sequence characters, and ? to match a single character"));
|
||||
filterSizer->Add(filterTextCtrl, wxSizerFlags().Border(wxALL, 5));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SetCurrentFilename();
|
||||
}
|
||||
|
||||
void ArchiveViewer::OnAbout(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxMessageBox(wxString::Format(_("%s - created by Philip Taylor (philip@wildfiregames.com / philip@zaynar.demon.co.uk)"), g_ProgramNameVersion.c_str()),
|
||||
_("About"), wxOK|wxCENTRE|wxICON_INFORMATION);
|
||||
}
|
||||
|
||||
ArchiveViewer::~ArchiveViewer()
|
||||
{
|
||||
delete m_BARStream;
|
||||
delete m_BARReader;
|
||||
}
|
||||
|
||||
void ArchiveViewer::OnClose(wxCloseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
m_FileHistory.Save(*wxConfigBase::Get());
|
||||
}
|
||||
|
||||
//struct compare_bar {
|
||||
// bool operator()(const BAREntry& x, const BAREntry& y) { return (x.filename < y.filename); }
|
||||
//};
|
||||
|
||||
void ArchiveViewer::RedrawFileList(bool keepSelection)
|
||||
{
|
||||
if (!m_BARReader || !m_BARStream)
|
||||
// No BAR file loaded
|
||||
return;
|
||||
|
||||
std::vector<bool> filesSelected;
|
||||
filesSelected.resize(m_CachedFileData.size(), false);
|
||||
|
||||
// If desired, remember a list of selected and focussed items
|
||||
int focussed = -1;
|
||||
if (keepSelection)
|
||||
{
|
||||
// Iterate through selected items
|
||||
long item = m_FileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
while (item != -1)
|
||||
{
|
||||
filesSelected[ m_FileListCtrl->GetItemData(item) ] = true;
|
||||
item = m_FileListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
}
|
||||
|
||||
// Remember single focussed item
|
||||
item = m_FileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
|
||||
if (item != -1)
|
||||
focussed = m_FileListCtrl->GetItemData(item);
|
||||
}
|
||||
|
||||
wxString filter;
|
||||
enum { NONE, SUBSTRING, WILDCARD } filterType = NONE; // attempt to use most efficient matching system
|
||||
if (m_Filter.Len())
|
||||
{
|
||||
if (m_Filter.Contains(_T("*")) || m_Filter.Contains(_T("?")))
|
||||
{
|
||||
filterType = WILDCARD;
|
||||
filter = _T("*") + m_Filter.Lower() + _T("*"); // match any substring, and case insensitive
|
||||
}
|
||||
else
|
||||
{
|
||||
filterType = SUBSTRING;
|
||||
filter = m_Filter.Lower();
|
||||
}
|
||||
}
|
||||
|
||||
m_FileListCtrl->Freeze();
|
||||
m_FileListCtrl->DeleteAllItems();
|
||||
|
||||
for (size_t i = 0; i < m_CachedFileData.size(); ++i)
|
||||
{
|
||||
if ( (filterType == SUBSTRING && !m_CachedFileData[i].NameLower.Contains(filter))
|
||||
|| (filterType == WILDCARD && !m_CachedFileData[i].NameLower.Matches(filter)))
|
||||
continue;
|
||||
|
||||
wxListItem info;
|
||||
info.SetText(m_CachedFileData[i].Name);
|
||||
info.SetData((long)i);
|
||||
info.SetId((long)i);
|
||||
if (keepSelection)
|
||||
{
|
||||
int state = (filesSelected[i] ? wxLIST_STATE_SELECTED : 0) | (focussed == (int)i ? wxLIST_STATE_FOCUSED : 0);
|
||||
if (state)
|
||||
{
|
||||
info.SetState(state);
|
||||
info.SetStateMask(wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
|
||||
}
|
||||
}
|
||||
long idx = m_FileListCtrl->InsertItem(info);
|
||||
wxASSERT(idx != -1);
|
||||
m_FileListCtrl->SetItem(idx, 1, m_CachedFileData[i].Size);
|
||||
m_FileListCtrl->SetItem(idx, 2, m_CachedFileData[i].Date);
|
||||
}
|
||||
|
||||
m_FileListCtrl->Thaw();
|
||||
}
|
||||
|
||||
|
||||
void ArchiveViewer::UpdateFileList()
|
||||
{
|
||||
if (!m_BARReader || !m_BARStream)
|
||||
// No BAR file loaded
|
||||
return;
|
||||
|
||||
wxRegEx commas (_T("(\\d+)(\\d{3})"), wxRE_ADVANCED); // for comma-ising filesizes
|
||||
|
||||
// Get list of all files
|
||||
// std::vector<BAREntry> files = m_BARReader->GetFileList(); // non-constref copy, so we can sort it
|
||||
// std::sort(files.begin(), files.end(), compare_bar());
|
||||
const std::vector<BAREntry>& files = m_BARReader->GetFileList();
|
||||
|
||||
m_CachedFileData.clear();
|
||||
m_CachedFileData.resize(files.size());
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i)
|
||||
{
|
||||
m_CachedFileData[i].Name = wxString( utf16tow(files[i].filename).c_str() );
|
||||
m_CachedFileData[i].NameLower = m_CachedFileData[i].Name.Lower();
|
||||
|
||||
m_CachedFileData[i].Size = wxString::Format(_T("%d"), files[i].filesize);
|
||||
while (commas.Replace(&m_CachedFileData[i].Size, _T("\\1,\\2"))) ;
|
||||
|
||||
if (files[i].modified.year == 0)
|
||||
m_CachedFileData[i].Date = _("Unknown");
|
||||
else
|
||||
{
|
||||
wxDateTime date (files[i].modified.day, (wxDateTime::Month)(wxDateTime::Jan + files[i].modified.month-1), files[i].modified.year,
|
||||
files[i].modified.hour, files[i].modified.minute, files[i].modified.second, files[i].modified.msecond);
|
||||
m_CachedFileData[i].Date = wxString::Format(
|
||||
_T("%s %s.%03d"),
|
||||
date.FormatISODate().c_str(),
|
||||
date.FormatISOTime().c_str(),
|
||||
date.GetMillisecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveViewer::OpenFile(const wxString& filename)
|
||||
{
|
||||
wxFFileInputStream* fileStream = new wxFFileInputStream(filename);
|
||||
if (! fileStream->Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open file"));
|
||||
delete fileStream;
|
||||
return;
|
||||
}
|
||||
|
||||
SeekableInputStream* stream = new SeekableInputStreamFromWx(fileStream);
|
||||
BARReader* reader = new BARReader(*stream);
|
||||
if (! reader->Initialise())
|
||||
{
|
||||
wxLogError(_("Failed to read BAR file"));
|
||||
delete reader;
|
||||
delete stream;
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete old data, replace with new data
|
||||
delete m_BARStream;
|
||||
delete m_BARReader;
|
||||
m_BARStream = stream;
|
||||
m_BARReader = reader;
|
||||
|
||||
UpdateFileList();
|
||||
RedrawFileList(false);
|
||||
|
||||
m_FileHistory.AddFileToHistory(filename);
|
||||
SetCurrentFilename(filename);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ArchiveViewer::OnExtractSelected(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
ExtractFiles(true);
|
||||
}
|
||||
|
||||
void ArchiveViewer::OnExtractAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
ExtractFiles(false);
|
||||
}
|
||||
|
||||
void ArchiveViewer::ExtractFiles(bool onlySelected)
|
||||
{
|
||||
long item = -1;
|
||||
|
||||
if (onlySelected)
|
||||
{
|
||||
// Find the first selected item, and make sure there is actually a selection
|
||||
item = m_FileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
|
||||
if (item == -1)
|
||||
{
|
||||
wxMessageBox(_("Please select one or more files to extract."), _("No files selected"), wxICON_INFORMATION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Work out where to extract the files to:
|
||||
|
||||
// Assume same as last place, else default (from registry), else cwd
|
||||
wxString dir = m_LastExtractDir;
|
||||
if (! dir.Len())
|
||||
{
|
||||
dir = GetDefaultOpenDirectory();
|
||||
if (! dir.Len())
|
||||
dir = wxFileName::GetCwd();
|
||||
}
|
||||
|
||||
// Let user choose final location
|
||||
wxDirDialog dlg(this, wxDirSelectorPromptStr, dir);
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
// Remember the selection
|
||||
dir = dlg.GetPath();
|
||||
dir += wxFileName::GetPathSeparator();
|
||||
m_LastExtractDir = dir;
|
||||
wxFileName rootDir (dir);
|
||||
|
||||
|
||||
// Construct a list of items to extract:
|
||||
const std::vector<BAREntry>& files = m_BARReader->GetFileList();
|
||||
std::vector<int> selection;
|
||||
if (onlySelected)
|
||||
{
|
||||
while (item != -1)
|
||||
{
|
||||
selection.push_back(m_FileListCtrl->GetItemData(item)); // item was set at top of function
|
||||
item = m_FileListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extract all files
|
||||
for (int i = 0; i < (int)files.size(); ++i)
|
||||
selection.push_back(i);
|
||||
}
|
||||
|
||||
bool aborted = false;
|
||||
|
||||
{
|
||||
// Create the required directory structure:
|
||||
|
||||
// Extract the list of all directories:
|
||||
std::set<std::wstring> dirs;
|
||||
for (size_t sel = 0; sel < selection.size(); ++sel)
|
||||
{
|
||||
const BAREntry& file = files[selection[sel]];
|
||||
wxString filename = wxString( utf16tow(file.filename).c_str() );
|
||||
int lastSlash = filename.Find(_T('\\'), true);
|
||||
if (lastSlash != -1)
|
||||
dirs.insert(filename.Mid(0, lastSlash+1).wc_str());
|
||||
}
|
||||
|
||||
// Construct the directory tree:
|
||||
for (std::set<std::wstring>::iterator it = dirs.begin(); it != dirs.end(); ++it)
|
||||
{
|
||||
// Append name-in-archive to target root directory, one dir
|
||||
// at a time, calling mkdir at each step if necessary
|
||||
wxFileName fullFilePath (rootDir);
|
||||
wxFileName filePath (it->c_str(), wxPATH_WIN);
|
||||
const wxArrayString& filePathDirs = filePath.GetDirs();
|
||||
for (size_t i = 0; i < filePathDirs.Count(); ++i)
|
||||
{
|
||||
fullFilePath.AppendDir(filePathDirs[i]);
|
||||
if (! wxDirExists(fullFilePath.GetPath()))
|
||||
wxMkdir(fullFilePath.GetPath());
|
||||
}
|
||||
}
|
||||
|
||||
// Create progress display
|
||||
wxProgressDialog progress (_("Extracting files"), _("Please wait"), (int)selection.size(), this,
|
||||
wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
|
||||
|
||||
// Repeat for each selection file
|
||||
for (size_t sel = 0; sel < selection.size(); ++sel)
|
||||
{
|
||||
const BAREntry& file = files[selection[sel]];
|
||||
|
||||
if (! progress.Update((int)sel, wxString::Format(_("Extracting %s"), file.filename.c_str())))
|
||||
{
|
||||
aborted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Append name-in-archive to target root directory, one dir
|
||||
// at a time, calling mkdir at each step if necessary
|
||||
wxFileName filePath (wxString( utf16tow(file.filename).c_str() ), wxPATH_WIN);
|
||||
filePath.MakeAbsolute(rootDir.GetPath());
|
||||
|
||||
// Output to disk
|
||||
wxFFileOutputStream outStream(filePath.GetFullPath());
|
||||
if (! outStream.Ok())
|
||||
wxLogError(wxString::Format(_("Error opening output file %s"), filePath.GetFullPath().c_str()));
|
||||
else
|
||||
{
|
||||
SeekableOutputStreamFromWx str (outStream);
|
||||
m_BARReader->TransferFile(file, str);
|
||||
outStream.Close();
|
||||
|
||||
// Set the file's timestamps to match the one specified in the archive
|
||||
if (file.modified.year != 0)
|
||||
{
|
||||
wxDateTime date (file.modified.day, (wxDateTime::Month)(wxDateTime::Jan + file.modified.month-1), file.modified.year,
|
||||
file.modified.hour, file.modified.minute, file.modified.second, file.modified.msecond);
|
||||
filePath.SetTimes(NULL, &date, &date);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aborted)
|
||||
wxMessageBox(_("Extraction aborted."), _("Stopped"));
|
||||
else
|
||||
wxMessageBox(_("Extraction complete."), _("Finished"));
|
||||
}
|
||||
|
||||
|
||||
void ArchiveViewer::OnEnablePreview(wxCommandEvent& event)
|
||||
{
|
||||
m_PreviewEnabled = event.IsChecked();
|
||||
|
||||
if (m_PreviewEnabled)
|
||||
{
|
||||
// Make sure the window's not far too small
|
||||
if (GetSize().GetWidth() < 700)
|
||||
SetSize(-1, -1, 900, -1); // nobody is still using 800x600, are they?
|
||||
|
||||
m_Splitter->SetDefaultSashPosition(600);
|
||||
m_Splitter->SplitVertically(m_Splitter->GetWindow1(), m_PreviewWindow);
|
||||
}
|
||||
else
|
||||
m_Splitter->Unsplit();
|
||||
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
void ArchiveViewer::UpdatePreview(long item)
|
||||
{
|
||||
if (! m_PreviewEnabled)
|
||||
return;
|
||||
|
||||
// If the user opens a large archive file, enables the preview, selects the
|
||||
// bottom file, and presses shift+home, it attempts to redraw the preview
|
||||
// for every single file in sequence. That takes forever; so provide a way
|
||||
// to abort the preview update.
|
||||
if (wxGetKeyState(WXK_ESCAPE))
|
||||
return;
|
||||
|
||||
// If none is specified, preview the first selected item
|
||||
if (item == -1)
|
||||
item = m_FileListCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
|
||||
if (item == -1) // none selected
|
||||
return;
|
||||
|
||||
const BAREntry& file = m_BARReader->GetFileList()[ m_FileListCtrl->GetItemData(item) ];
|
||||
SeekableInputStream* str = m_BARReader->GetFile(file);
|
||||
m_PreviewWindow->PreviewFile(wxString(utf16tow(file.filename).c_str()), *str);
|
||||
delete str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ArchiveViewer::OnOpen(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxString path, name;
|
||||
if (GetCurrentFilename().IsOk())
|
||||
{
|
||||
path = GetCurrentFilename().GetPath();
|
||||
name = GetCurrentFilename().GetFullName();
|
||||
}
|
||||
else
|
||||
{
|
||||
path = GetDefaultOpenDirectory();
|
||||
}
|
||||
|
||||
wxFileDialog dlg (this, _("Select archive file to open"), path, name, _("BAR files (*.bar)|*.bar|All files (*.*)|*.*"), wxOPEN);
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
OpenFile(dlg.GetPath());
|
||||
}
|
||||
|
||||
void ArchiveViewer::OnMRUFile(wxCommandEvent& event)
|
||||
{
|
||||
wxString file (m_FileHistory.GetHistoryFile(event.GetId() - wxID_FILE1));
|
||||
if (file.Len())
|
||||
OpenFile(file);
|
||||
}
|
||||
|
||||
void ArchiveViewer::OnQuit(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void ArchiveViewer::SetCurrentFilename(wxFileName filename)
|
||||
{
|
||||
m_CurrentFilename = filename;
|
||||
|
||||
if (filename.IsOk())
|
||||
SetTitle(m_WindowTitle + _T(" - ") + filename.GetFullName());
|
||||
else
|
||||
SetTitle(m_WindowTitle);
|
||||
}
|
||||
|
||||
wxString ArchiveViewer::GetDefaultOpenDirectory()
|
||||
{
|
||||
// TODO
|
||||
/*
|
||||
wxRegKey key (_T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Games\\Age of Empires 3\\1.0"));
|
||||
if (key.Exists())
|
||||
{
|
||||
wxString dir;
|
||||
|
||||
// The path might be the default value under the AppPath key, or it
|
||||
// might be the AppPath value; so check both.
|
||||
wxRegKey subkey (key, _T("AppPath"));
|
||||
if (subkey.Exists())
|
||||
{
|
||||
if (subkey.QueryValue(_T(""), dir)) // default value
|
||||
return dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key.HasValue(_T("AppPath")) && key.QueryValue(_T("AppPath"), dir))
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return _T("");
|
||||
}
|
||||
|
||||
void ArchiveViewer::SetFilter(const wxString& filter)
|
||||
{
|
||||
m_Filter = filter;
|
||||
RedrawFileList(true);
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "FileHistory/FileHistory.h"
|
||||
#include "SnapSplitterWindow/SnapSplitterWindow.h"
|
||||
#include "FilePreviewer.h"
|
||||
|
||||
#include "wx/filename.h"
|
||||
#include "wx/listctrl.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
class BARReader;
|
||||
struct BAREntry;
|
||||
class SeekableInputStream;
|
||||
}
|
||||
|
||||
class ArchiveViewer : public wxFrame
|
||||
{
|
||||
public:
|
||||
ArchiveViewer(wxWindow* parent);
|
||||
~ArchiveViewer();
|
||||
|
||||
void OnOpen(wxCommandEvent& event);
|
||||
void OnMRUFile(wxCommandEvent& event);
|
||||
void OnQuit(wxCommandEvent& event);
|
||||
void OnExtractSelected(wxCommandEvent& event);
|
||||
void OnExtractAll(wxCommandEvent& event);
|
||||
void OnEnablePreview(wxCommandEvent& event);
|
||||
void OnAbout(wxCommandEvent& event);
|
||||
|
||||
void OnClose(wxCloseEvent& event);
|
||||
|
||||
void SetFilter(const wxString& filter);
|
||||
void UpdatePreview(long index = -1);
|
||||
|
||||
private:
|
||||
void OpenFile(const wxString& filename);
|
||||
void UpdateFileList(); // must be called after opening a new file
|
||||
void RedrawFileList(bool keepSelection);
|
||||
|
||||
void ExtractFiles(bool onlySelected);
|
||||
|
||||
void SetCurrentFilename(wxFileName filename = wxString());
|
||||
wxFileName GetCurrentFilename() { return m_CurrentFilename; }
|
||||
|
||||
wxString GetDefaultOpenDirectory();
|
||||
|
||||
wxFileName m_CurrentFilename;
|
||||
wxString m_WindowTitle;
|
||||
|
||||
wxString m_Filter;
|
||||
bool m_PreviewEnabled;
|
||||
FilePreviewer* m_PreviewWindow;
|
||||
SnapSplitterWindow* m_Splitter;
|
||||
|
||||
wxString m_LastExtractDir;
|
||||
|
||||
// wxStatusBar* m_StatusBar;
|
||||
|
||||
wxListCtrl* m_FileListCtrl;
|
||||
DatafileIO::SeekableInputStream* m_BARStream;
|
||||
DatafileIO::BARReader* m_BARReader;
|
||||
|
||||
struct FileData {
|
||||
wxString NameLower; // for filtering
|
||||
wxString Name;
|
||||
wxString Size;
|
||||
wxString Date;
|
||||
};
|
||||
std::vector<FileData> m_CachedFileData;
|
||||
|
||||
FileHistory m_FileHistory;
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
@ -1,259 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "FilePreviewer.h"
|
||||
|
||||
#include "DatafileIO/XMB/XMB.h"
|
||||
#include "DatafileIO/DDT/DDT.h"
|
||||
|
||||
#include "wx/sound.h"
|
||||
#include "wx/image.h"
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
class ImagePanel : public /*wxPanel*/wxScrolledWindow
|
||||
{
|
||||
public:
|
||||
ImagePanel(wxWindow* parent, const wxImage& img)
|
||||
: m_Bmp(img),
|
||||
// wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(img.GetWidth(), img.GetHeight()))
|
||||
wxScrolledWindow(parent)
|
||||
{
|
||||
SetScrollbars(1, 1, img.GetWidth(), img.GetHeight());
|
||||
}
|
||||
|
||||
void OnPaint(wxPaintEvent& WXUNUSED(event))
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
dc.Clear();
|
||||
if (m_Bmp.Ok())
|
||||
{
|
||||
dc.DrawBitmap(m_Bmp, CalcScrolledPosition(wxPoint(0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
wxBitmap m_Bmp;
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(ImagePanel, /*wxPanel*/wxScrolledWindow)
|
||||
EVT_PAINT(ImagePanel::OnPaint)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FilePreviewer::FilePreviewer(wxWindow* parent)
|
||||
: wxPanel(parent), m_ContentPanel(NULL)
|
||||
{
|
||||
m_MainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(m_MainSizer);
|
||||
}
|
||||
|
||||
enum FileType
|
||||
{
|
||||
UNKNOWN,
|
||||
XMB,
|
||||
XML,
|
||||
DDT,
|
||||
WAV,
|
||||
UNKNOWN_TEXT
|
||||
};
|
||||
|
||||
void FilePreviewer::PreviewFile(const wxString& filename, SeekableInputStream& stream)
|
||||
{
|
||||
if (m_ContentPanel)
|
||||
{
|
||||
m_MainSizer->Detach(m_ContentPanel);
|
||||
m_ContentPanel->Destroy();
|
||||
}
|
||||
|
||||
Freeze();
|
||||
|
||||
m_ContentPanel = new wxPanel(this);
|
||||
m_MainSizer->Add(m_ContentPanel, wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxStaticText* fileInfo = new wxStaticText(m_ContentPanel, wxID_ANY, wxString::Format(_("Filename: %s"), filename.c_str()));
|
||||
sizer->Add(fileInfo, wxSizerFlags().Border(wxALL, 5));
|
||||
m_ContentPanel->SetSizer(sizer);
|
||||
|
||||
FileType type = UNKNOWN;
|
||||
|
||||
wxString extn;
|
||||
int dot = filename.Find(_T('.'), true);
|
||||
if (dot != -1)
|
||||
extn = filename.Mid(dot).Lower();
|
||||
|
||||
#define X(x) extn==_T(x)
|
||||
if (X(".xmb"))
|
||||
type = XMB;
|
||||
|
||||
else if (X(".xml") || X(".lgt") || X(".dtd") || X(".shp"))
|
||||
type = XML;
|
||||
|
||||
else if (X(".ddt"))
|
||||
type = DDT;
|
||||
|
||||
else if (X(".wav"))
|
||||
type = WAV;
|
||||
|
||||
else if (X(".txt") || X(".xs") || X(".psh") || X(".vsh") || X(".hlsl") || X(".inc"))
|
||||
type = UNKNOWN_TEXT;
|
||||
#undef X
|
||||
|
||||
wxString extraFileInfo;
|
||||
|
||||
if (type == XMB)
|
||||
{
|
||||
DatafileIO::XMBFile* file = DatafileIO::XMBFile::LoadFromXMB(stream);
|
||||
std::wstring text = file->SaveAsXML();
|
||||
delete file;
|
||||
|
||||
wxString wtext (text.c_str(), text.length());
|
||||
wtext = L"<!-- converted from XMB to XML -->\n" + wtext;
|
||||
|
||||
sizer->Add(new wxTextCtrl(m_ContentPanel, wxID_ANY, wtext, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_READONLY | wxHSCROLL | wxTE_RICH), // use RICH so we can display big files
|
||||
wxSizerFlags().Expand().Proportion(1).Border(wxALL, 5));
|
||||
|
||||
extraFileInfo = _("Format: XMB");
|
||||
}
|
||||
|
||||
else if (type == XML || type == UNKNOWN_TEXT)
|
||||
{
|
||||
void* buf;
|
||||
size_t bufSize;
|
||||
if (! stream.AcquireBuffer(buf, bufSize))
|
||||
{
|
||||
wxFAIL_MSG(_T("Buffer acquisition failed"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume UTF8, and convert to wxString
|
||||
wxString wtext ((char*)buf, wxConvUTF8, bufSize);
|
||||
|
||||
sizer->Add(new wxTextCtrl(m_ContentPanel, wxID_ANY, wtext, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_READONLY | wxHSCROLL),
|
||||
wxSizerFlags().Expand().Proportion(1).Border(wxALL, 5));
|
||||
|
||||
if (type == XML)
|
||||
extraFileInfo = _("Format: XML");
|
||||
else
|
||||
extraFileInfo = _("Format: unidentified text");
|
||||
}
|
||||
}
|
||||
|
||||
else if (type == DDT)
|
||||
{
|
||||
DDTFile file(stream);
|
||||
if (! file.Read(DDTFile::DDT))
|
||||
{
|
||||
wxLogError(_("Failed to read DDT file"));
|
||||
}
|
||||
else
|
||||
{
|
||||
wxArrayString formatStrings;
|
||||
switch (file.m_Type_Usage) {
|
||||
case DDTFile::BUMP: formatStrings.Add(_("normal map")); break;
|
||||
case DDTFile::CUBE: formatStrings.Add(_("cube map")); break;
|
||||
}
|
||||
switch (file.m_Type_Alpha) {
|
||||
case DDTFile::NONE: formatStrings.Add(_("no alpha")); break;
|
||||
// case DDTFile::PLAYER: formatStrings.Add(_("player colour")); break;
|
||||
// case DDTFile::TRANS: formatStrings.Add(_("transparency")); break;
|
||||
case DDTFile::BLEND: formatStrings.Add(_("terrain blend")); break;
|
||||
}
|
||||
switch (file.m_Type_Format) {
|
||||
case DDTFile::BGRA: formatStrings.Add(_("32-bit BGRA")); break;
|
||||
case DDTFile::DXT1: formatStrings.Add(_("DXT1")); break;
|
||||
case DDTFile::GREY: formatStrings.Add(_("8-bit grey")); break;
|
||||
case DDTFile::DXT3: formatStrings.Add(_("DXT3")); break;
|
||||
case DDTFile::NORMSPEC: formatStrings.Add(_("specular+normal")); break;
|
||||
}
|
||||
|
||||
wxString formatString;
|
||||
for (size_t i = 0; i < formatStrings.GetCount(); ++i)
|
||||
formatString += (i ? _T(", ") : _T("")) + formatStrings[i];
|
||||
if (! formatString.Len())
|
||||
formatString = _("unknown");
|
||||
|
||||
extraFileInfo = wxString::Format(_("Format: DDT texture\nSubformat: %d %d %d (%s)"),
|
||||
file.m_Type_Usage, file.m_Type_Alpha, file.m_Type_Format, formatString.c_str());
|
||||
|
||||
void* buffer;
|
||||
int width, height;
|
||||
if (! file.GetImageData(buffer, width, height, false))
|
||||
{
|
||||
extraFileInfo += _("\n(Unrecognised format - unable to display)");
|
||||
}
|
||||
else
|
||||
{
|
||||
sizer->Add(new ImagePanel(m_ContentPanel, wxImage(width, height, (unsigned char*)buffer)),
|
||||
wxSizerFlags().Expand().Proportion(1).Border(wxALL, 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (type == WAV)
|
||||
{
|
||||
void* buf;
|
||||
size_t bufSize;
|
||||
if (! stream.AcquireBuffer(buf, bufSize))
|
||||
{
|
||||
wxFAIL_MSG(_T("Buffer acquisition failed"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// HACK: If we destroy the sound object before it's finished playing,
|
||||
// it deallocates the audio data and fails to play (or crashes).
|
||||
// (That's assuming we fix wxSound to not just leak the memory.)
|
||||
// So, just use a static object, and hope it stops playing before
|
||||
// the program is exited.
|
||||
// The wxSound-from memory constructor does not exist on OS X, so
|
||||
// just show a warning there.
|
||||
#ifdef __APPLE__
|
||||
wxFAIL_MSG(_T("WAV playback not available on Mac OS X"));
|
||||
#else
|
||||
static wxSound snd;
|
||||
snd.Stop();
|
||||
// HACK, FIXME, XXX: I'd like to call the wx people idiots for
|
||||
// having different API:s on different platforms, as well as for
|
||||
// having public non-API methods.
|
||||
#if __APPLE__
|
||||
snd.~wxSound();
|
||||
new (&snd) wxSound((int)bufSize, (const wxByte*)buf);
|
||||
#else
|
||||
snd.Create((int)bufSize, (const wxByte*)buf);
|
||||
#endif
|
||||
snd.Play();
|
||||
#endif
|
||||
stream.ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
extraFileInfo = _("Format: WAV audio");
|
||||
}
|
||||
|
||||
fileInfo->SetLabel(fileInfo->GetLabel() + _T("\n") + extraFileInfo);
|
||||
|
||||
m_MainSizer->Layout();
|
||||
|
||||
Thaw();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "DatafileIO/Stream/Stream.h"
|
||||
|
||||
class FilePreviewer : public wxPanel
|
||||
{
|
||||
public:
|
||||
FilePreviewer(wxWindow* parent);
|
||||
|
||||
// stream can be deleted by callers after this function returns
|
||||
void PreviewFile(const wxString& filename, DatafileIO::SeekableInputStream& stream);
|
||||
|
||||
private:
|
||||
wxPanel* m_ContentPanel; // gets deleted and rebuilt when previewing a new file
|
||||
wxSizer* m_MainSizer;
|
||||
};
|
@ -1,367 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "FileConverter.h"
|
||||
|
||||
#include "Misc/Version.h"
|
||||
|
||||
#include "AtlasObject/AtlasObject.h"
|
||||
#include "DatafileIO/XMB/XMB.h"
|
||||
#include "DatafileIO/DDT/DDT.h"
|
||||
#include "DatafileIO/Stream/wx.h"
|
||||
#include "DatafileIO/Stream/Memory.h"
|
||||
|
||||
#include "wx/wfstream.h"
|
||||
#include "wx/progdlg.h"
|
||||
#include "wx/config.h"
|
||||
#include "wx/regex.h"
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
//#define QUIET
|
||||
|
||||
enum FileType { XMB, XML, DDT, TGA };
|
||||
|
||||
const wxChar* xmlExtensions[] = {
|
||||
_T("amt"), _T("blueprint"), _T("d3dconfig"), _T("dmg"), _T("effect"), _T("impacteffect"),
|
||||
_T("lgt"), _T("multieffect"), _T("multips"), _T("multirs"),_T("multitechnique"),
|
||||
_T("multitss"), _T("multivs"), _T("particle"), _T("physics"), _T("ps"), _T("rs"),
|
||||
_T("tactics"), _T("technique"), _T("tss"), _T("vs"), _T("xml"),
|
||||
NULL };
|
||||
|
||||
bool IsXMLExtension(const wxString& str)
|
||||
{
|
||||
const wxChar** e = xmlExtensions;
|
||||
while (*e)
|
||||
if (str == wxString(_T(".")) + *e++)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConvertFiles(const wxArrayString& files, wxWindow* parent);
|
||||
|
||||
bool ConvertFile(const wxString& sourceFilename, FileType sourceType,
|
||||
const wxString& targetFilename, FileType targetType,
|
||||
XMLReader* io);
|
||||
|
||||
FileConverter::FileConverter(wxWindow* parent)
|
||||
: wxFrame(parent, wxID_ANY, wxString::Format(_("%s - File Converter"), g_ProgramNameVersion.c_str()))
|
||||
{
|
||||
SetIcon(wxIcon(_T("ICON_FileConverter")));
|
||||
|
||||
m_Transient = true;
|
||||
|
||||
bool succeeded = false;
|
||||
wxApp* app = wxTheApp;
|
||||
if (app->argc > 1)
|
||||
{
|
||||
wxArrayString files;
|
||||
for (int i = 1; i < app->argc; ++i)
|
||||
files.Add(app->argv[i]);
|
||||
succeeded = ConvertFiles(files, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxConfigBase* cfg = wxConfigBase::Get(false);
|
||||
wxString defaultDir;
|
||||
if (cfg)
|
||||
cfg->Read(_T("File Converter/OpenDir"), &defaultDir);
|
||||
|
||||
wxString extns = _("Recognised files");
|
||||
extns += _T(" (*.xmb, *.ddt, *.xml, *.tga)|*.xmb;*.ddt;*.xml;*.tga");
|
||||
// Add all the extra XML types
|
||||
const wxChar** e = xmlExtensions;
|
||||
while (*e)
|
||||
{
|
||||
extns += _T(";*.");
|
||||
extns += *e++;
|
||||
}
|
||||
extns += wxString(_T("|")) + _("All files") + _T(" (*.*)|*.*");
|
||||
|
||||
wxFileDialog dlg (this, _("Select file(s) to convert"), defaultDir, _T(""),
|
||||
extns, wxOPEN|/*wxFILE_MUST_EXIST|*/wxMULTIPLE); // for some reason, it complains that files don't exist when they actually do...
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
{
|
||||
wxArrayString files;
|
||||
dlg.GetPaths(files);
|
||||
succeeded = ConvertFiles(files, this);
|
||||
|
||||
if (cfg)
|
||||
cfg->Write(_T("File Converter/OpenDir"), dlg.GetDirectory());
|
||||
}
|
||||
else
|
||||
{
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
wxLog::FlushActive(); // ensure errors are displayed before the "finished" message
|
||||
|
||||
#ifndef QUIET
|
||||
if (succeeded)
|
||||
wxMessageBox(_("Conversion complete."), _("Finished"), wxOK|wxICON_INFORMATION);
|
||||
#endif
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool FileConverter::Show(bool show)
|
||||
{
|
||||
if (m_Transient)
|
||||
return true;
|
||||
else
|
||||
return wxFrame::Show(show);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ConvertFiles(const wxArrayString& files, wxWindow* parent)
|
||||
{
|
||||
XMLReader io; // TODO: don't create this unless necessary, because Xerces is slow
|
||||
|
||||
wxProgressDialog progress(_("Converting files"), _("Please wait"), (int)files.GetCount(), parent,
|
||||
wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
|
||||
|
||||
for (size_t i = 0; i < files.GetCount(); ++i)
|
||||
{
|
||||
wxString sourceFilename = files[i];
|
||||
wxString targetFilename;
|
||||
FileType sourceType, targetType;
|
||||
|
||||
if (! progress.Update((int)i, wxString::Format(_("Converting %s"), sourceFilename.c_str())))
|
||||
return false;
|
||||
|
||||
wxString sourceExtn, sourceName;
|
||||
{
|
||||
int dot = sourceFilename.Find(_T('.'), true);
|
||||
if (dot == -1)
|
||||
{
|
||||
wxLogError(_("No file extension for %s - don't know how to convert"), sourceFilename.c_str());
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceExtn = sourceFilename.Mid(dot).Lower();
|
||||
sourceName = sourceFilename.Mid(0, dot); // no extension
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceExtn == _T(".xmb"))
|
||||
{
|
||||
sourceType = XMB;
|
||||
targetType = XML;
|
||||
// Ignore trailing .xmb
|
||||
targetFilename = sourceName;
|
||||
}
|
||||
else if (sourceExtn == _T(".ddt"))
|
||||
{
|
||||
sourceType = DDT;
|
||||
targetType = TGA; // TODO: allow BMP
|
||||
targetFilename = sourceName + _T(".tga");
|
||||
}
|
||||
else if (sourceExtn == _T(".tga"))
|
||||
{
|
||||
sourceType = TGA; // TODO: allow BMP
|
||||
targetType = DDT;
|
||||
targetFilename = sourceName + _T(".ddt");
|
||||
}
|
||||
else if (IsXMLExtension(sourceExtn))
|
||||
{
|
||||
sourceType = XML;
|
||||
targetType = XMB;
|
||||
// Add a trailing .xmb (in addition to the normal .xml/etc)
|
||||
targetFilename = sourceFilename + _T(".xmb");
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError(_("Unknown file extension for %s - don't know how to convert"), sourceFilename.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
#ifndef QUIET
|
||||
// Warn about overwriting files
|
||||
if (wxFile::Exists(targetFilename))
|
||||
{
|
||||
int ret = wxMessageBox(wxString::Format(_("Output file already exists: %s\nOverwrite file?"), targetFilename.c_str()), _("Overwrite?"), wxYES_NO|wxCANCEL);
|
||||
if (ret == wxCANCEL) return false;
|
||||
else if (ret == wxNO) continue;
|
||||
else { /* carry on converting */ }
|
||||
}
|
||||
#endif
|
||||
|
||||
// Do the actual conversion
|
||||
ConvertFile(sourceFilename, sourceType, targetFilename, targetType, &io);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConvertFile(const wxString& sourceFilename, FileType sourceType,
|
||||
const wxString& targetFilename, FileType targetType,
|
||||
XMLReader* io)
|
||||
{
|
||||
// Open input file (in binary read mode)
|
||||
wxFFileInputStream file (sourceFilename);
|
||||
if (! file.Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open input file %s"), sourceFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
// Decompress input file if necessary (for any file type)
|
||||
//std::auto_ptr<InputStream> inStream (new Maybel33tInputStream(new SeekableInputStreamFromWx(file)));
|
||||
Maybel33tInputStream inStream (new SeekableInputStreamFromWx(file));
|
||||
if (! inStream.IsOk())
|
||||
{
|
||||
wxLogError(_("Failed to decompress input file %s"), sourceFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle XMB<->XML conversions
|
||||
if (sourceType == XMB || sourceType == XML)
|
||||
{
|
||||
std::auto_ptr<XMBFile> data (NULL);
|
||||
|
||||
// Read data with the appropriate format
|
||||
if (sourceType == XML)
|
||||
{
|
||||
// if (! io) io = new XMLReader(); // TODO - see earlier comment
|
||||
data.reset(io->LoadFromXML(inStream));
|
||||
data->format = XMBFile::AOE3; // TODO: let users control this?
|
||||
}
|
||||
else if (sourceType == XMB)
|
||||
{
|
||||
data.reset(XMBFile::LoadFromXMB(inStream));
|
||||
}
|
||||
|
||||
// Write data with the appropriate format
|
||||
if (targetType == XML)
|
||||
{
|
||||
std::wstring xml = data->SaveAsXML();
|
||||
wxFFileOutputStream out(targetFilename, _T("w")); // open in text mode
|
||||
if (! out.Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open output file %s"), targetFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output with UTF-8 encoding
|
||||
xml = L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + xml;
|
||||
wxCharBuffer buf = wxString(xml.c_str()).mb_str(wxConvUTF8);
|
||||
out.Write(buf.data(), strlen(buf.data()));
|
||||
}
|
||||
else if (targetType == XMB)
|
||||
{
|
||||
wxFFileOutputStream out (targetFilename, _T("wb"));
|
||||
if (! out.Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open output file %s"), targetFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SeekableOutputStreamFromWx out2 (out);
|
||||
data->SaveAsXMB(out2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (sourceType == DDT)
|
||||
{
|
||||
DDTFile ddt(inStream);
|
||||
if (! ddt.Read(DDTFile::DDT))
|
||||
{
|
||||
wxLogError(_("Failed to read DDT file %s"), sourceFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
// Stick some format-identifying data just before the extension
|
||||
// part of the filename:
|
||||
wxRegEx re (_T("(.*)\\."), wxRE_ADVANCED);
|
||||
wxString newFilename = targetFilename;
|
||||
re.ReplaceFirst(&newFilename,
|
||||
wxString::Format(_T("\\1.(%d,%d,%d,%d)."),
|
||||
ddt.m_Type_Usage, ddt.m_Type_Alpha, ddt.m_Type_Format, ddt.m_Type_Levels));
|
||||
|
||||
wxFFileOutputStream out(newFilename, _T("wb"));
|
||||
if (! out.Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open output file %s"), newFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
SeekableOutputStreamFromWx out2 (out);
|
||||
ddt.SaveFile(out2, DDTFile::TGA);
|
||||
}
|
||||
|
||||
else if (sourceType == TGA)
|
||||
{
|
||||
DDTFile ddt(inStream);
|
||||
if (! ddt.Read(DDTFile::TGA))
|
||||
{
|
||||
wxLogError(_("Failed to read TGA file %s"), sourceFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
// Extract the format-identifying data from just before the extension
|
||||
// part of the filename:
|
||||
wxRegEx re (_T("\\.\\((\\d+),(\\d+),(\\d+),(\\d+)\\)\\."), wxRE_ADVANCED); // regexps in C++ are ugly :-(
|
||||
wxString newFilename = targetFilename;
|
||||
if (re.Matches(newFilename.c_str()))
|
||||
{
|
||||
wxASSERT(re.GetMatchCount() == 5);
|
||||
long l0 = 0, l1 = 0, l2 = 0, l3 = 0;
|
||||
if (re.GetMatch(newFilename, 1).ToLong(&l0)
|
||||
&& re.GetMatch(newFilename, 2).ToLong(&l1)
|
||||
&& re.GetMatch(newFilename, 3).ToLong(&l2)
|
||||
&& re.GetMatch(newFilename, 4).ToLong(&l3))
|
||||
{
|
||||
ddt.m_Type_Usage = (DDTFile::Type_Usage)l0;
|
||||
ddt.m_Type_Alpha = (DDTFile::Type_Alpha)l1;
|
||||
ddt.m_Type_Format = (DDTFile::Type_Format)l2;
|
||||
ddt.m_Type_Levels = l3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: ask the user for settings? or at least be more helpful
|
||||
wxLogError(_("Invalid filename - should be something.(n,n,n,n).tga"));
|
||||
return false;
|
||||
}
|
||||
// Remove the format-identifying part when constructing the DDT filename
|
||||
re.ReplaceFirst(&newFilename, _T("."));
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError(_("Invalid filename - should be something.(n,n,n,n).tga"));
|
||||
return false;
|
||||
}
|
||||
|
||||
wxFFileOutputStream out(newFilename, _T("wb"));
|
||||
if (! out.Ok())
|
||||
{
|
||||
wxLogError(_("Failed to open output file %s"), newFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
SeekableOutputStreamFromWx out2 (out);
|
||||
ddt.SaveFile(out2, DDTFile::DDT);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
wxFAIL_MSG(_T("TODO"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class FileConverter : public wxFrame
|
||||
{
|
||||
public:
|
||||
FileConverter(wxWindow* parent);
|
||||
virtual bool Show(bool);
|
||||
|
||||
private:
|
||||
bool m_Transient; // if true, the window won't be shown (since it's assumed to have been destroyed immediately)
|
||||
};
|
@ -24,8 +24,6 @@
|
||||
#include "General/Datafile.h"
|
||||
|
||||
#include "ActorEditor/ActorEditor.h"
|
||||
#include "ArchiveViewer/ArchiveViewer.h"
|
||||
#include "FileConverter/FileConverter.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "ErrorReporter/ErrorReporter.h"
|
||||
|
||||
@ -203,15 +201,11 @@ public:
|
||||
|
||||
// Display the appropriate window
|
||||
wxFrame* frame;
|
||||
#define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else
|
||||
MAYBE(ActorEditor)
|
||||
#ifdef USE_AOE3ED
|
||||
MAYBE(ArchiveViewer)
|
||||
MAYBE(FileConverter)
|
||||
#endif
|
||||
#undef MAYBE
|
||||
// else
|
||||
if (g_InitialWindowType == _T("ScenarioEditor"))
|
||||
if (g_InitialWindowType == _T("ActorEditor"))
|
||||
{
|
||||
frame = new ActorEditor(NULL);
|
||||
}
|
||||
else if (g_InitialWindowType == _T("ScenarioEditor"))
|
||||
{
|
||||
m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand);
|
||||
frame = new ScenarioEditor(NULL, *m_ScriptInterface);
|
||||
|
@ -1,18 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const wxString g_ProgramNameVersion = _("AoE3Ed v0.9");
|
@ -1,142 +0,0 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "BAR.h"
|
||||
#include "Util.h"
|
||||
#include "Stream/Stream.h"
|
||||
#include "Stream/Memory.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
BARReader::BARReader(SeekableInputStream& stream)
|
||||
: m_Stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
#define CHECK(expr) if (!(expr)) { assert(!(expr)); return false; }
|
||||
|
||||
bool BARReader::Initialise()
|
||||
{
|
||||
assert(m_FileList.size() == 0); // Only call Init once
|
||||
|
||||
char head[4];
|
||||
m_Stream.Read(head, 4);
|
||||
CHECK(strncmp(head, "ESPN", 4) == 0);
|
||||
|
||||
uint32_t unknown;
|
||||
m_Stream.Read(&unknown, 4);
|
||||
CHECK(unknown == 2);
|
||||
|
||||
m_Stream.Read(&unknown, 4);
|
||||
CHECK(unknown == 0x44332211);
|
||||
|
||||
for (int i = 0; i < 66; ++i)
|
||||
{
|
||||
m_Stream.Read(&unknown, 4);
|
||||
CHECK(unknown == 0);
|
||||
}
|
||||
|
||||
m_Stream.Read(&unknown, 4); // TODO: checksum?
|
||||
|
||||
uint32_t numFiles, filetableOffset;
|
||||
m_Stream.Read(&numFiles, 4);
|
||||
m_Stream.Read(&filetableOffset, 4);
|
||||
|
||||
m_Stream.Read(&unknown, 4);
|
||||
// 0 in AoE3
|
||||
// Non-zero (e.g. 466a800a, 8df1e438) in AoEO; purpose unknown
|
||||
|
||||
m_Stream.Seek(filetableOffset, Stream::FROM_START);
|
||||
|
||||
utf16string rootName = ReadUString(m_Stream);
|
||||
uint32_t numRootFiles;
|
||||
m_Stream.Read(&numRootFiles, 4);
|
||||
CHECK(numRootFiles == numFiles);
|
||||
|
||||
m_FileList.reserve(numFiles);
|
||||
for (uint32_t i = 0; i < numFiles; ++i)
|
||||
{
|
||||
BAREntry file;
|
||||
|
||||
uint32_t offset, length0, length1;
|
||||
m_Stream.Read(&offset, 4);
|
||||
m_Stream.Read(&length0, 4);
|
||||
m_Stream.Read(&length1, 4);
|
||||
CHECK(length0 == length1); // ??
|
||||
|
||||
file.offset = offset;
|
||||
file.filesize = length0;
|
||||
|
||||
// Ranges: 1995-2005, 1-12, 0-5, 1-31, 0+10-23, 0-59, 0-59, 0-999
|
||||
m_Stream.Read(&file.modified.year, 2);
|
||||
m_Stream.Read(&file.modified.month, 2);
|
||||
m_Stream.Read(&file.modified.dayofweek, 2);
|
||||
m_Stream.Read(&file.modified.day, 2);
|
||||
m_Stream.Read(&file.modified.hour, 2);
|
||||
m_Stream.Read(&file.modified.minute, 2);
|
||||
m_Stream.Read(&file.modified.second, 2);
|
||||
m_Stream.Read(&file.modified.msecond, 2);
|
||||
|
||||
if (file.modified.year == 0xCCCC) // no date specified
|
||||
memset(&file.modified, 0, sizeof(file.modified));
|
||||
|
||||
file.filename = rootName + ReadUString(m_Stream);
|
||||
|
||||
m_FileList.push_back(file);
|
||||
}
|
||||
|
||||
// TODO: check this is really EOF
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct buffer_releaser
|
||||
{
|
||||
SeekableInputStream* stream;
|
||||
|
||||
};
|
||||
|
||||
SeekableInputStream* BARReader::GetFile(const BAREntry& file) const
|
||||
{
|
||||
void* buffer;
|
||||
size_t size;
|
||||
m_Stream.Seek((off_t)file.offset, Stream::FROM_START);
|
||||
m_Stream.AcquireBuffer(buffer, size, file.filesize);
|
||||
return new SeekableInputStream_mem((char*)buffer, size, new SeekableInputStream_mem::Releaser_StreamBuffer(&m_Stream));
|
||||
}
|
||||
|
||||
void BARReader::TransferFile(const BAREntry& file, OutputStream& stream) const
|
||||
{
|
||||
m_Stream.Seek((off_t)file.offset, Stream::FROM_START);
|
||||
const size_t bufSize = 128*1024; // people
|
||||
static char* buffer[bufSize];
|
||||
size_t bytesLeft = file.filesize;
|
||||
while (bytesLeft)
|
||||
{
|
||||
size_t bytesRead = m_Stream.Read(buffer, std::min(bufSize, bytesLeft));
|
||||
stream.Write(buffer, bytesRead);
|
||||
bytesLeft -= bytesRead;
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../Util.h"
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
class SeekableInputStream;
|
||||
class OutputStream;
|
||||
|
||||
struct BAREntry
|
||||
{
|
||||
utf16string filename; // includes root name - e.g. "Data\tactics\warwagon.tactics.xmb"
|
||||
size_t filesize; // in bytes
|
||||
struct {
|
||||
unsigned short year, month, day, dayofweek; // 2005 etc, 1..12, 1..31, 0..6 (from Sunday)
|
||||
unsigned short hour, minute, second, msecond; // 1..24, 0..59, 0..59, 0..999
|
||||
// ...unless there's no date specified, in which case these will all be zero
|
||||
} modified;
|
||||
|
||||
private: // implementation details
|
||||
friend class BARReader;
|
||||
size_t offset; // (assume all BARs are <4GB)
|
||||
};
|
||||
|
||||
class BARReader
|
||||
{
|
||||
public:
|
||||
BARReader(SeekableInputStream& stream);
|
||||
|
||||
// Read the header and file table.
|
||||
bool Initialise();
|
||||
|
||||
// Get list of files.
|
||||
const std::vector<BAREntry>& GetFileList() const { return m_FileList; }
|
||||
|
||||
// Get a seekable input stream for the specified file.
|
||||
// Multiple file streams can be open at the same time.
|
||||
SeekableInputStream* GetFile(const BAREntry& file) const;
|
||||
// Copy a file's contents from the archive to an output stream
|
||||
void TransferFile(const BAREntry& file, OutputStream& stream) const;
|
||||
|
||||
private:
|
||||
SeekableInputStream& m_Stream;
|
||||
std::vector<BAREntry> m_FileList;
|
||||
|
||||
BARReader& operator=(const BARReader&);
|
||||
};
|
||||
|
||||
}
|
@ -1,467 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "DDT.h"
|
||||
|
||||
#include "Stream/Stream.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include "IL/il.h"
|
||||
#include "IL/ilu.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
DDTFile::DDTFile(SeekableInputStream& stream)
|
||||
: m_Stream(stream)
|
||||
{
|
||||
// TODO: allow multiple nested DDTFiles, with ref-counted init
|
||||
ilInit();
|
||||
ilGenImages(1, &m_Image);
|
||||
}
|
||||
|
||||
DDTFile::~DDTFile()
|
||||
{
|
||||
ilDeleteImages(1, &m_Image);
|
||||
ilShutDown();
|
||||
}
|
||||
|
||||
|
||||
struct DDTImage
|
||||
{
|
||||
int width, height;
|
||||
off_t offset;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
#ifdef USE_DEVIL_DXT
|
||||
static void LoadDXT(int dxtType, unsigned char* oldData);
|
||||
static void SaveDXT(int dxtType); // saves the currently bound image
|
||||
static void SwizzleAGBR();
|
||||
#endif
|
||||
#ifdef USE_HACKED_DEVIL
|
||||
static void ToggleOrigin(); // urgh
|
||||
#endif
|
||||
|
||||
bool DDTFile::Read(FileType type)
|
||||
{
|
||||
ilBindImage(m_Image);
|
||||
|
||||
if (type == DDT)
|
||||
{
|
||||
char head[4];
|
||||
m_Stream.Read(head, 4);
|
||||
if (strncmp(head, "RTS3", 4) != 0)
|
||||
{
|
||||
// TODO: report helpful error message
|
||||
return false;
|
||||
}
|
||||
|
||||
char format[3];
|
||||
m_Stream.Read(format, 3);
|
||||
m_Type_Usage = (Type_Usage)format[0];
|
||||
m_Type_Alpha = (Type_Alpha)format[1];
|
||||
m_Type_Format = (Type_Format)format[2];
|
||||
|
||||
char mipmapLevels;
|
||||
m_Stream.Read(&mipmapLevels, 1);
|
||||
m_Type_Levels = mipmapLevels;
|
||||
|
||||
uint32_t baseWidth, baseHeight;
|
||||
m_Stream.Read(&baseWidth, 4);
|
||||
m_Stream.Read(&baseHeight, 4);
|
||||
|
||||
int numImagesPerLevel = (m_Type_Usage == CUBE ? 6 : 1);
|
||||
int numImages = mipmapLevels * numImagesPerLevel;
|
||||
|
||||
std::vector<DDTImage> Images;
|
||||
|
||||
Images.resize(numImages);
|
||||
for (int i = 0; i < numImages; ++i)
|
||||
{
|
||||
int width = baseWidth >> (i/numImagesPerLevel); if (width < 1) width = 1;
|
||||
int height = baseHeight >> (i/numImagesPerLevel); if (height < 1) height = 1;
|
||||
uint32_t offset, length;
|
||||
m_Stream.Read(&offset, 4);
|
||||
m_Stream.Read(&length, 4);
|
||||
Images[i].width = width;
|
||||
Images[i].height = height;
|
||||
Images[i].offset = offset;
|
||||
Images[i].length = length;
|
||||
}
|
||||
|
||||
// Read the first image. (TODO: cubemaps)
|
||||
|
||||
int w = Images[0].width;
|
||||
int h = Images[0].height;
|
||||
ilTexImage(w,h,1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
unsigned char* newData = (unsigned char*)ilGetData();
|
||||
switch (m_Type_Format)
|
||||
{
|
||||
case BGRA:
|
||||
{
|
||||
unsigned char* oldData = new unsigned char[w*h*4];
|
||||
m_Stream.Read(oldData, w*h*4);
|
||||
for (int i = 0; i < w*h; ++i)
|
||||
{
|
||||
newData[i*4+0] = oldData[i*4+2];
|
||||
newData[i*4+1] = oldData[i*4+1];
|
||||
newData[i*4+2] = oldData[i*4+0];
|
||||
newData[i*4+3] = oldData[i*4+3];
|
||||
}
|
||||
delete[] oldData;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef USE_DEVIL_DXT
|
||||
case DXT1:
|
||||
case DXT3:
|
||||
case NORMSPEC:
|
||||
{
|
||||
int dxtType = (m_Type_Format == DXT1 ? 1 : m_Type_Format == DXT3 ? 3 : 5);
|
||||
int pixPerByte = (m_Type_Format == DXT1 ? 2 : 1);
|
||||
unsigned char* oldData = new unsigned char[w*h/pixPerByte];
|
||||
m_Stream.Read(oldData, w*h/pixPerByte);
|
||||
LoadDXT(dxtType, oldData);
|
||||
if (m_Type_Format == NORMSPEC)
|
||||
SwizzleAGBR();
|
||||
delete[] oldData;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case GREY:
|
||||
{
|
||||
unsigned char* oldData = new unsigned char[w*h];
|
||||
m_Stream.Read(oldData, w*h);
|
||||
for (int i = 0; i < w*h; ++i)
|
||||
{
|
||||
newData[i*4+0] =
|
||||
newData[i*4+1] =
|
||||
newData[i*4+2] = oldData[i];
|
||||
newData[i*4+3] = 255;
|
||||
}
|
||||
delete[] oldData;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
//assert(! "Unhandled format");
|
||||
ilClearColour(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
ilClearImage();
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef USE_HACKED_DEVIL
|
||||
ToggleOrigin(); // use this instead of iluFlip because we don't want to change the actual data
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (type == TGA)
|
||||
{
|
||||
void* buffer;
|
||||
size_t size;
|
||||
m_Stream.AcquireBuffer(buffer, size);
|
||||
ilLoadL(IL_TGA, buffer, (ILuint)size);
|
||||
m_Stream.ReleaseBuffer(buffer);
|
||||
ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE);
|
||||
iluFlipImage();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(! "Invalid type");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DDTFile::GetImageData(void*& buffer, int& width, int& height, bool realAlpha)
|
||||
{
|
||||
ilBindImage(m_Image);
|
||||
|
||||
width = ilGetInteger(IL_IMAGE_WIDTH);
|
||||
height = ilGetInteger(IL_IMAGE_HEIGHT);
|
||||
if (realAlpha)
|
||||
{
|
||||
buffer = malloc(width*height * 4);
|
||||
memcpy(buffer, ilGetData(), width*height * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = malloc(width*height * 3 * 2);
|
||||
unsigned char* newData = (unsigned char*)buffer;
|
||||
unsigned char* oldData = (unsigned char*)ilGetData();
|
||||
|
||||
for (int i = 0; i < width*height; ++i)
|
||||
{
|
||||
newData[i*3+0] = oldData[i*4+0];
|
||||
newData[i*3+1] = oldData[i*4+1];
|
||||
newData[i*3+2] = oldData[i*4+2];
|
||||
}
|
||||
for (int i = 0; i < width*height; ++i)
|
||||
{
|
||||
newData[(i+width*height)*3+0] =
|
||||
newData[(i+width*height)*3+1] =
|
||||
newData[(i+width*height)*3+2] = oldData[i*4+3];
|
||||
}
|
||||
}
|
||||
|
||||
height *= 2;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// DevIL code: (slightly nasty, since DevIL doesn't seem to be flexible enough
|
||||
// to do what I need it to do...)
|
||||
|
||||
struct ILOutputStream
|
||||
{
|
||||
static OutputStream* stream;
|
||||
static ILHANDLE ILAPIENTRY Open(const ILstring)
|
||||
{
|
||||
return (void*)-1;
|
||||
}
|
||||
static void ILAPIENTRY Close(ILHANDLE)
|
||||
{
|
||||
}
|
||||
static ILint ILAPIENTRY Putc(ILubyte c, ILHANDLE)
|
||||
{
|
||||
stream->Write(&c, 1);
|
||||
return c;
|
||||
}
|
||||
static ILint ILAPIENTRY Seek(ILHANDLE, ILint /*offset*/, ILint /*whence*/)
|
||||
{
|
||||
assert(! "Not implemented");
|
||||
return 0;
|
||||
}
|
||||
static ILint ILAPIENTRY Tell(ILHANDLE)
|
||||
{
|
||||
return stream->Tell();
|
||||
}
|
||||
static ILint ILAPIENTRY Write(const void* data, ILuint size, ILuint count, ILHANDLE)
|
||||
{
|
||||
if (size*count)
|
||||
stream->Write(data, size*count);
|
||||
return count;
|
||||
}
|
||||
};
|
||||
OutputStream* ILOutputStream::stream = NULL;
|
||||
|
||||
extern "C" {
|
||||
extern ILboolean ilSaveTargaF(ILHANDLE File);
|
||||
// because DevIL doesn't want to write to things that aren't
|
||||
// really files, so we have to use its internal writing functions
|
||||
extern void iSetOutputFile(ILHANDLE File);
|
||||
}
|
||||
|
||||
bool DDTFile::SaveFile(OutputStream& stream, FileType outputType)
|
||||
{
|
||||
ilBindImage(m_Image);
|
||||
|
||||
ilSetWrite(&ILOutputStream::Open, &ILOutputStream::Close, &ILOutputStream::Putc,
|
||||
&ILOutputStream::Seek, &ILOutputStream::Tell, &ILOutputStream::Write);
|
||||
iSetOutputFile(NULL); // make sure it's using the right output functions
|
||||
|
||||
ILOutputStream::stream = &stream;
|
||||
|
||||
if (outputType == TGA)
|
||||
{
|
||||
ilSaveTargaF(NULL);
|
||||
}
|
||||
else if (outputType == DDT)
|
||||
{
|
||||
int bpp;
|
||||
switch (m_Type_Format)
|
||||
{
|
||||
case BGRA: bpp = 32; break;
|
||||
case GREY: bpp = 8; break;
|
||||
case DXT1: bpp = 4; break;
|
||||
case DXT3: bpp = 8; break;
|
||||
case NORMSPEC: bpp = 8; break;
|
||||
default: assert(! "Invalid format"); return false;
|
||||
}
|
||||
|
||||
stream.Write("RTS3", 4);
|
||||
|
||||
char format[4];
|
||||
format[0] = (char)m_Type_Usage;
|
||||
format[1] = (char)m_Type_Alpha;
|
||||
format[2] = (char)m_Type_Format;
|
||||
format[3] = (char)m_Type_Levels;
|
||||
stream.Write(format, 4);
|
||||
|
||||
uint32_t baseWidth, baseHeight;
|
||||
baseWidth = ilGetInteger(IL_IMAGE_WIDTH);
|
||||
baseHeight = ilGetInteger(IL_IMAGE_HEIGHT);
|
||||
stream.Write(&baseWidth, 4);
|
||||
stream.Write(&baseHeight, 4);
|
||||
|
||||
int numImagesPerLevel = 1; // TODO: cubemaps
|
||||
int numImages = m_Type_Levels * numImagesPerLevel;
|
||||
uint32_t imgOffset = 16 + 8*numImages;
|
||||
|
||||
for (int i = 0; i < numImages; ++i)
|
||||
{
|
||||
int width = baseWidth >> (i/numImagesPerLevel); if (width < 1) width = 1;
|
||||
int height = baseHeight >> (i/numImagesPerLevel); if (height < 1) height = 1;
|
||||
uint32_t length = width*height * bpp / 8;
|
||||
stream.Write(&imgOffset, 4);
|
||||
stream.Write(&length, 4);
|
||||
imgOffset += length;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numImages; ++i)
|
||||
{
|
||||
int width = baseWidth >> (i/numImagesPerLevel); if (width < 1) width = 1;
|
||||
int height = baseHeight >> (i/numImagesPerLevel); if (height < 1) height = 1;
|
||||
|
||||
ilBindImage(m_Image);
|
||||
|
||||
ILuint img = ilCloneCurImage();
|
||||
ilBindImage(img);
|
||||
iluImageParameter(ILU_FILTER, ILU_SCALE_BOX); // TODO - proper mipmapping
|
||||
iluScale(width, height, 1);
|
||||
|
||||
switch (m_Type_Format)
|
||||
{
|
||||
case BGRA:
|
||||
{
|
||||
unsigned char* newData = new unsigned char[width*height*4];
|
||||
unsigned char* oldData = (unsigned char*)ilGetData();
|
||||
for (int i = 0; i < width*height; ++i)
|
||||
{
|
||||
newData[i*4+0] = oldData[i*4+2];
|
||||
newData[i*4+1] = oldData[i*4+1];
|
||||
newData[i*4+2] = oldData[i*4+0];
|
||||
newData[i*4+3] = oldData[i*4+3];
|
||||
}
|
||||
stream.Write(newData, width*height*4);
|
||||
delete[] newData;
|
||||
break;
|
||||
}
|
||||
case GREY:
|
||||
{
|
||||
unsigned char* newData = new unsigned char[width*height];
|
||||
unsigned char* oldData = (unsigned char*)ilGetData();
|
||||
for (int i = 0; i < width*height; ++i)
|
||||
{
|
||||
newData[i] = oldData[i*4+0];
|
||||
}
|
||||
stream.Write(newData, width*height);
|
||||
delete[] newData;
|
||||
break;
|
||||
}
|
||||
#ifdef USE_DEVIL_DXT
|
||||
case DXT1:
|
||||
SaveDXT(1);
|
||||
break;
|
||||
case DXT3:
|
||||
SaveDXT(3);
|
||||
break;
|
||||
case NORMSPEC:
|
||||
SwizzleAGBR();
|
||||
SaveDXT(5);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
ilDeleteImages(1, &img);
|
||||
}
|
||||
}
|
||||
|
||||
ilResetWrite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Evilness:
|
||||
#ifdef USE_HACKED_DEVIL
|
||||
#include "IL/devil_internal_exports.h"
|
||||
extern "C"
|
||||
{
|
||||
extern ILboolean DecompressDXT1();
|
||||
extern ILboolean DecompressDXT3();
|
||||
extern ILboolean DecompressDXT5();
|
||||
extern ILuint Compress(ILimage* Image, ILenum DXTCFormat);
|
||||
extern ILimage* iCurImage;
|
||||
}
|
||||
|
||||
static void ToggleOrigin()
|
||||
{
|
||||
iCurImage->Origin = (iCurImage->Origin == IL_ORIGIN_UPPER_LEFT ? IL_ORIGIN_LOWER_LEFT : IL_ORIGIN_UPPER_LEFT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DEVIL_DXT
|
||||
extern "C"
|
||||
{
|
||||
extern ILubyte* CompData;
|
||||
extern ILint Depth, Width, Height;
|
||||
extern ILimage* Image;
|
||||
}
|
||||
|
||||
static void LoadDXT(int dxtType, unsigned char* oldData)
|
||||
{
|
||||
// More evilness, that assumes a lot about DevIL's internals:
|
||||
CompData = (ILubyte*)oldData;
|
||||
Image = iCurImage;
|
||||
Width = Image->Width;
|
||||
Height = Image->Height;
|
||||
Depth = Image->Depth;
|
||||
|
||||
switch (dxtType)
|
||||
{
|
||||
case 1: DecompressDXT1(); break;
|
||||
case 3: DecompressDXT3(); break;
|
||||
case 5: DecompressDXT5(); break;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
CompData = NULL;
|
||||
Image = NULL;
|
||||
}
|
||||
|
||||
static void SwizzleAGBR()
|
||||
{
|
||||
ILubyte* data = ilGetData();
|
||||
ILint pixels = ilGetInteger(IL_IMAGE_WIDTH)*ilGetInteger(IL_IMAGE_HEIGHT);
|
||||
for (ILint i = 0; i < pixels; ++i)
|
||||
{
|
||||
ILubyte t = data[i*4+0];
|
||||
data[i*4+0] = data[i*4+3];
|
||||
data[i*4+3] = t;
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveDXT(int dxtType)
|
||||
{
|
||||
Compress(ilGetCurImage(), dxtType==1 ? IL_DXT1 : dxtType==3 ? IL_DXT3 : IL_DXT5);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,91 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef unsigned int ILuint;
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
class SeekableInputStream;
|
||||
class OutputStream;
|
||||
|
||||
class DDTFile
|
||||
{
|
||||
public:
|
||||
enum FileType { TGA, BMP, DDT };
|
||||
|
||||
// Initialises the file, but doesn't actually read anything
|
||||
DDTFile(SeekableInputStream& stream);
|
||||
|
||||
~DDTFile();
|
||||
|
||||
// Attempts to read the file, and returns true on success
|
||||
bool Read(FileType type);
|
||||
|
||||
bool SaveFile(OutputStream& stream, FileType outputType);
|
||||
|
||||
// All arguments are outputs. buffer is allocated by malloc, and
|
||||
// must be freed by the caller. If realAlpha is true, the buffer
|
||||
// will be RGBA, else it'll be RGB (with height doubled and the alpha
|
||||
// stuck on the bottom)
|
||||
bool GetImageData(void*& buffer, int& width, int& height, bool realAlpha);
|
||||
|
||||
enum Type_Usage {
|
||||
UNK0 = 0, // ??
|
||||
UNK1 = 1, // ??
|
||||
BUMP = 6,
|
||||
UNK2 = 7, // ??
|
||||
CUBE = 8
|
||||
};
|
||||
enum Type_Alpha {
|
||||
NONE = 0, // ??
|
||||
PLAYER = 1, // ?? }
|
||||
TRANS = 4, // ?? } these names are completely incorrect
|
||||
BLEND = 8, // mostly unused
|
||||
};
|
||||
enum Type_Format {
|
||||
BGRA = 1,
|
||||
DXT1 = 4,
|
||||
GREY = 7,
|
||||
DXT3 = 8,
|
||||
NORMSPEC = 9 // DXT5, with spec in R channel, XYZ in AGB channels.
|
||||
// (See e.g. http://www.ati.com/developer/NormalMapCompression.pdf)
|
||||
};
|
||||
|
||||
// (These values are not guaranteed to actually be in the enums)
|
||||
Type_Usage m_Type_Usage;
|
||||
Type_Alpha m_Type_Alpha;
|
||||
Type_Format m_Type_Format;
|
||||
|
||||
int m_Type_Levels; // of mipmaps
|
||||
|
||||
// struct Image
|
||||
// {
|
||||
// int width, height;
|
||||
// off_t offset;
|
||||
// size_t length;
|
||||
// };
|
||||
// std::vector<Image> m_Images;
|
||||
ILuint m_Image;
|
||||
|
||||
private:
|
||||
SeekableInputStream& m_Stream;
|
||||
|
||||
DDTFile& operator=(const DDTFile&);
|
||||
};
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
#include "../Util.h"
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <memory.h>
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
SeekableInputStream_mem::SeekableInputStream_mem(char* data, size_t size, Releaser* releaser)
|
||||
: m_Data(data), m_Size(size), m_Cursor(0), m_Releaser(releaser)
|
||||
{
|
||||
}
|
||||
|
||||
SeekableInputStream_mem::~SeekableInputStream_mem()
|
||||
{
|
||||
m_Releaser->release(m_Data);
|
||||
delete m_Releaser;
|
||||
}
|
||||
|
||||
off_t SeekableInputStream_mem::Tell() const
|
||||
{
|
||||
return m_Cursor;
|
||||
}
|
||||
|
||||
bool SeekableInputStream_mem::IsOk() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void SeekableInputStream_mem::Seek(off_t pos, Stream::whence mode)
|
||||
{
|
||||
if (mode == FROM_START)
|
||||
m_Cursor = pos;
|
||||
else if (mode == FROM_CURRENT)
|
||||
m_Cursor += pos;
|
||||
else if (mode == FROM_END)
|
||||
m_Cursor = (off_t)m_Size - pos;
|
||||
}
|
||||
|
||||
size_t SeekableInputStream_mem::Read(void* buffer, size_t size)
|
||||
{
|
||||
if (m_Cursor >= (off_t)m_Size)
|
||||
return 0;
|
||||
|
||||
size_t amount = size;
|
||||
if (m_Cursor + amount > m_Size)
|
||||
amount = m_Size - m_Cursor;
|
||||
|
||||
std::copy(m_Data+m_Cursor, m_Data+m_Cursor+amount, (char*)buffer);
|
||||
m_Cursor += (off_t)amount;
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
bool SeekableInputStream_mem::AcquireBuffer(void*& buffer, size_t& size, size_t max_size)
|
||||
{
|
||||
buffer = m_Data + m_Cursor;
|
||||
size = m_Size - m_Cursor;
|
||||
if (size > max_size) size = max_size;
|
||||
return true;
|
||||
}
|
||||
void SeekableInputStream_mem::ReleaseBuffer(void* /*buffer*/)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Maybel33tInputStream::Maybel33tInputStream(SeekableInputStream* stream)
|
||||
: m_Stream(NULL)
|
||||
{
|
||||
char head[8];
|
||||
size_t bytes = stream->Read(head, 8);
|
||||
if (bytes == 8 && strncmp(head, "l33t", 4) == 0)
|
||||
{
|
||||
uint32_t uncompressedSize;
|
||||
memcpy(&uncompressedSize, &head[4], 4);
|
||||
|
||||
void* buffer;
|
||||
size_t size;
|
||||
if (! stream->AcquireBuffer(buffer, size))
|
||||
{
|
||||
assert(!"Buffer acquisition unsuccessful");
|
||||
}
|
||||
else
|
||||
{
|
||||
char* uncompressedBuffer = new char[uncompressedSize];
|
||||
uLongf newUncomprSize = (uLongf)uncompressedSize;
|
||||
int err = uncompress((Bytef*)uncompressedBuffer, &newUncomprSize, (Bytef*)buffer, (uLong)size);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
assert(!"Decompression failed");
|
||||
delete[] uncompressedBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(newUncomprSize == uncompressedSize);
|
||||
m_Stream = new SeekableInputStream_mem(uncompressedBuffer, uncompressedSize, new SeekableInputStream_mem::Releaser_NewArray);
|
||||
}
|
||||
stream->ReleaseBuffer(buffer);
|
||||
}
|
||||
delete stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream->Seek(-(off_t)bytes, FROM_CURRENT);
|
||||
m_Stream = stream;
|
||||
}
|
||||
|
||||
}
|
||||
Maybel33tInputStream::~Maybel33tInputStream()
|
||||
{
|
||||
delete m_Stream;
|
||||
}
|
||||
|
||||
bool Maybel33tInputStream::IsOk() const
|
||||
{
|
||||
return (m_Stream != NULL);
|
||||
}
|
||||
|
||||
off_t Maybel33tInputStream::Tell() const { return m_Stream->Tell(); }
|
||||
void Maybel33tInputStream::Seek(off_t pos, Stream::whence mode) { m_Stream->Seek(pos, mode); }
|
||||
size_t Maybel33tInputStream::Read(void* buffer, size_t size) { return m_Stream->Read(buffer, size); }
|
||||
bool Maybel33tInputStream::AcquireBuffer(void*& buffer, size_t& size, size_t max_size) { return m_Stream->AcquireBuffer(buffer, size, max_size); }
|
||||
void Maybel33tInputStream::ReleaseBuffer(void* buffer) { m_Stream->ReleaseBuffer(buffer); }
|
@ -1,81 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
|
||||
class SeekableInputStream_mem : public SeekableInputStream
|
||||
{
|
||||
public:
|
||||
// 'Release' provides common buffer-release mechanisms, called
|
||||
// when this stream is destroyed
|
||||
struct Releaser {
|
||||
virtual ~Releaser() {}
|
||||
virtual void release(char* buffer) = 0;
|
||||
};
|
||||
struct Releaser_None : public Releaser {
|
||||
virtual void release(char* /*buffer*/) {};
|
||||
};
|
||||
struct Releaser_StreamBuffer : public Releaser {
|
||||
Releaser_StreamBuffer(InputStream* s) : stream(s) {}
|
||||
InputStream* stream;
|
||||
virtual void release(char* buffer) {
|
||||
stream->ReleaseBuffer(buffer);
|
||||
}
|
||||
};
|
||||
struct Releaser_NewArray : public Releaser {
|
||||
virtual void release(char* buffer) {
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
|
||||
SeekableInputStream_mem(char* data, size_t size, Releaser* releaser);
|
||||
~SeekableInputStream_mem();
|
||||
virtual off_t Tell() const;
|
||||
virtual bool IsOk() const;
|
||||
virtual void Seek(off_t pos, Stream::whence mode);
|
||||
virtual size_t Read(void* buffer, size_t size);
|
||||
virtual bool AcquireBuffer(void*& buffer, size_t& size, size_t max_size);
|
||||
virtual void ReleaseBuffer(void* buffer);
|
||||
private:
|
||||
Releaser* m_Releaser;
|
||||
char* m_Data;
|
||||
size_t m_Size;
|
||||
off_t m_Cursor;
|
||||
};
|
||||
|
||||
|
||||
// Magically decompresses l33t-compressed files.
|
||||
class Maybel33tInputStream : public SeekableInputStream
|
||||
{
|
||||
public:
|
||||
// Take ownership of a SeekableInputStream
|
||||
Maybel33tInputStream(SeekableInputStream* stream);
|
||||
~Maybel33tInputStream();
|
||||
|
||||
virtual off_t Tell() const;
|
||||
virtual bool IsOk() const;
|
||||
virtual void Seek(off_t pos, Stream::whence mode);
|
||||
virtual size_t Read(void* buffer, size_t size);
|
||||
virtual bool AcquireBuffer(void*& buffer, size_t& size, size_t max_size);
|
||||
virtual void ReleaseBuffer(void* buffer);
|
||||
private:
|
||||
SeekableInputStream* m_Stream;
|
||||
};
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <memory.h>
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
bool InputStream::AcquireBuffer(void*& buffer, size_t& size, size_t max_size)
|
||||
{
|
||||
std::string data;
|
||||
const size_t tempBufSize = 65536;
|
||||
static char tempBuffer[tempBufSize];
|
||||
size = 0;
|
||||
size_t bytesLeft = max_size;
|
||||
size_t bytesRead;
|
||||
while (bytesLeft > 0 && (bytesRead = Read(tempBuffer, std::min(bytesLeft, tempBufSize))) != 0)
|
||||
{
|
||||
size += bytesRead;
|
||||
bytesLeft -= bytesRead;
|
||||
data += std::string(tempBuffer, bytesRead);
|
||||
}
|
||||
|
||||
buffer = new char[size];
|
||||
memcpy(buffer, data.data(), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputStream::ReleaseBuffer(void* buffer)
|
||||
{
|
||||
delete[] (char*)buffer;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_STREAM
|
||||
#define INCLUDED_STREAM
|
||||
|
||||
/*
|
||||
Stream: A system for input/output of data, particularly with chained streams
|
||||
(e.g. file -> zlib decompressor -> data processor).
|
||||
|
||||
Similar to wxWidget's streams, but rewritten so that code can use this without
|
||||
requiring wx.
|
||||
|
||||
TODO: This concept might not actually be any good; consider alternatives.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <limits>
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
enum whence { FROM_START, FROM_END, FROM_CURRENT };
|
||||
|
||||
virtual ~Stream() {}
|
||||
virtual off_t Tell() const = 0;
|
||||
virtual bool IsOk() const = 0;
|
||||
};
|
||||
|
||||
class SeekableStream
|
||||
{
|
||||
public:
|
||||
virtual ~SeekableStream() {}
|
||||
virtual void Seek(off_t pos, Stream::whence mode) = 0;
|
||||
};
|
||||
|
||||
|
||||
class InputStream : public Stream
|
||||
{
|
||||
public:
|
||||
// Try to read up to 'size' bytes into buffer, and return the amount
|
||||
// actually read.
|
||||
virtual size_t Read(void* buffer, size_t size) = 0;
|
||||
|
||||
// Sets 'buffer' and 'size' to point to the data from the current cursor
|
||||
// position up to max_size bytes (or the end of the file, whichever is
|
||||
// reached first) and returns true if successful.
|
||||
// If a derived stream doesn't implement these, a default (which just
|
||||
// calls Read to get all the data) will be used instead. (It is implemented
|
||||
// in e.g. streams that already have a pointer to all the data, so they
|
||||
// don't need to do any memory copying.)
|
||||
virtual bool AcquireBuffer(void*& buffer, size_t& size, size_t max_size = std::numeric_limits<size_t>::max());
|
||||
virtual void ReleaseBuffer(void* buffer);
|
||||
};
|
||||
|
||||
class OutputStream : public Stream
|
||||
{
|
||||
public:
|
||||
virtual void Write(const void* buffer, size_t size) = 0;
|
||||
};
|
||||
|
||||
|
||||
// Specialisations to indicate that a stream allows seeking.
|
||||
class SeekableInputStream : public InputStream, public SeekableStream
|
||||
{
|
||||
};
|
||||
|
||||
class SeekableOutputStream : public OutputStream, public SeekableStream
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDED_STREAM
|
@ -1,115 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
#include "wx/mstream.h"
|
||||
#include "wx/zstream.h"
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
|
||||
// Wrappers around wx streams, so they can be used as [non-wx] Streams.
|
||||
// (This code is all inline so that the project can be compiled without
|
||||
// requiring wxWidgets.)
|
||||
|
||||
class SeekableInputStreamFromWx : public SeekableInputStream
|
||||
{
|
||||
public:
|
||||
// Take ownership of a wxInputStream
|
||||
SeekableInputStreamFromWx(wxInputStream* stream)
|
||||
: m_Stream(stream), m_Owner(true) {}
|
||||
|
||||
// Use an externally-owned wxInputStream
|
||||
SeekableInputStreamFromWx(wxInputStream& stream)
|
||||
: m_Stream(&stream), m_Owner(false) {}
|
||||
|
||||
~SeekableInputStreamFromWx()
|
||||
{
|
||||
if (m_Owner)
|
||||
delete m_Stream;
|
||||
}
|
||||
|
||||
virtual off_t Tell() const { return m_Stream->TellI(); }
|
||||
virtual bool IsOk() const { return m_Stream->IsOk(); }
|
||||
|
||||
virtual void Seek(off_t pos, Stream::whence mode)
|
||||
{
|
||||
m_Stream->SeekI(pos,
|
||||
mode==Stream::FROM_START ? wxFromStart
|
||||
: mode==Stream::FROM_END ? wxFromEnd
|
||||
: /*mode==Stream::FROM_CURRENT*/ wxFromCurrent);
|
||||
}
|
||||
|
||||
virtual size_t Read(void* buffer, size_t size)
|
||||
{
|
||||
m_Stream->Read(buffer, size);
|
||||
return m_Stream->LastRead();
|
||||
}
|
||||
|
||||
private:
|
||||
wxInputStream* m_Stream;
|
||||
bool m_Owner;
|
||||
};
|
||||
|
||||
|
||||
class SeekableOutputStreamFromWx : public SeekableOutputStream
|
||||
{
|
||||
public:
|
||||
// Take ownership of a wxInputStream
|
||||
SeekableOutputStreamFromWx(wxOutputStream* stream)
|
||||
: m_Stream(stream), m_Owner(true) {}
|
||||
|
||||
// Use an externally-owned wxInputStream
|
||||
SeekableOutputStreamFromWx(wxOutputStream& stream)
|
||||
: m_Stream(&stream), m_Owner(false) {}
|
||||
|
||||
~SeekableOutputStreamFromWx()
|
||||
{
|
||||
if (m_Owner)
|
||||
delete m_Stream;
|
||||
}
|
||||
|
||||
virtual off_t Tell() const
|
||||
{
|
||||
return m_Stream->TellO();
|
||||
}
|
||||
|
||||
virtual bool IsOk() const
|
||||
{
|
||||
return m_Stream->IsOk();
|
||||
}
|
||||
|
||||
virtual void Seek(off_t pos, Stream::whence mode)
|
||||
{
|
||||
m_Stream->SeekO(pos,
|
||||
mode==Stream::FROM_START ? wxFromStart
|
||||
: mode==Stream::FROM_END ? wxFromEnd
|
||||
: /*mode==Stream::FROM_CURRENT*/ wxFromCurrent);
|
||||
}
|
||||
|
||||
virtual void Write(const void* buffer, size_t size)
|
||||
{
|
||||
m_Stream->Write(buffer, size);
|
||||
}
|
||||
|
||||
private:
|
||||
wxOutputStream* m_Stream;
|
||||
bool m_Owner;
|
||||
};
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Util.h"
|
||||
#include "Stream/Stream.h"
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
utf16string DatafileIO::ReadUString(InputStream& stream)
|
||||
{
|
||||
uint32_t length;
|
||||
stream.Read(&length, 4);
|
||||
|
||||
utf16string ret;
|
||||
ret.resize(length);
|
||||
stream.Read(&ret[0], length*2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DatafileIO::WriteUString(OutputStream& stream, const utf16string& string)
|
||||
{
|
||||
uint32_t length = (uint32_t)string.length();
|
||||
stream.Write(&length, 4);
|
||||
stream.Write((utf16_t*)&string[0], length*2);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// TODO In reality, these two should be able to de/encode UTF-16 to/from UCS-4
|
||||
// instead of just treating UTF-16 as UCS-2
|
||||
|
||||
std::wstring DatafileIO::utf16tow(const utf16string &str)
|
||||
{
|
||||
return std::wstring(str.begin(), str.end());
|
||||
}
|
||||
|
||||
utf16string DatafileIO::wtoutf16(const std::wstring &str)
|
||||
{
|
||||
return utf16string(str.begin(), str.end());
|
||||
}
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_UTIL
|
||||
#define INCLUDED_UTIL
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef C_ASSERT
|
||||
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
|
||||
#endif
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// TODO: proper portability
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef std::wstring utf16string;
|
||||
typedef wchar_t utf16_t;
|
||||
#else
|
||||
typedef uint16_t utf16_t;
|
||||
typedef std::basic_string<utf16_t> utf16string;
|
||||
#endif
|
||||
|
||||
C_ASSERT(sizeof(int32_t) == 4);
|
||||
C_ASSERT(sizeof(uint32_t) == 4);
|
||||
C_ASSERT(sizeof(uint16_t) == 2);
|
||||
C_ASSERT(sizeof(utf16_t) == 2);
|
||||
|
||||
class InputStream;
|
||||
class OutputStream;
|
||||
|
||||
// Read/write 4-byte length + UCS-2 string
|
||||
utf16string ReadUString(InputStream& stream);
|
||||
void WriteUString(OutputStream& stream, const utf16string& string);
|
||||
|
||||
#ifdef _WIN32
|
||||
# define utf16tow(_str) _str
|
||||
# define wtoutf16(_str) _str
|
||||
#else
|
||||
std::wstring utf16tow(const utf16string &str);
|
||||
utf16string wtoutf16(const std::wstring &str);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // INCLUDED_UTIL
|
@ -1,672 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "XMB.h"
|
||||
#include "Stream/Stream.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
|
||||
#ifdef _MSC_VER // shut up about Xerces headers
|
||||
# pragma warning(disable: 4127) // conditional expression is constant
|
||||
# pragma warning(disable: 4671) // the copy constructor is inaccessible
|
||||
# pragma warning(disable: 4673) // throwing 'x' the following types will not be considered at the catch site
|
||||
# pragma warning(disable: 4244) // 'return' : conversion from '__w64 int' to 'unsigned long', possible loss of data
|
||||
# pragma warning(disable: 4267) // 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data
|
||||
#endif
|
||||
|
||||
|
||||
#include <xercesc/sax/ErrorHandler.hpp>
|
||||
#include <xercesc/sax/InputSource.hpp>
|
||||
#include <xercesc/sax/Locator.hpp>
|
||||
#include <xercesc/sax/SAXParseException.hpp>
|
||||
|
||||
#include <xercesc/sax2/Attributes.hpp>
|
||||
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
|
||||
#include <xercesc/util/BinInputStream.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
using namespace DatafileIO;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XMBFile functions:
|
||||
|
||||
static void DeallocateElement(XMLElement* el)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < el->childs.size(); ++i)
|
||||
DeallocateElement(el->childs[i]);
|
||||
|
||||
delete el;
|
||||
}
|
||||
|
||||
XMBFile::XMBFile()
|
||||
: root(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
XMBFile::~XMBFile()
|
||||
{
|
||||
DeallocateElement(root);
|
||||
}
|
||||
|
||||
// XMLReader init/shutdown:
|
||||
|
||||
DatafileIO::XMLReader::XMLReader()
|
||||
{
|
||||
XMLPlatformUtils::Initialize();
|
||||
}
|
||||
|
||||
DatafileIO::XMLReader::~XMLReader()
|
||||
{
|
||||
XMLPlatformUtils::Terminate();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Input utility functions:
|
||||
|
||||
#define READ(type, name) type name; stream.Read(&name, sizeof(type))
|
||||
#define READARRAY(type, n, name) type name[n]; stream.Read(&name, sizeof(type)*n)
|
||||
#define CHECK(expr, ret) if (!(expr)) { assert(!(expr)); return (ret); }
|
||||
|
||||
static void StringReplace(std::wstring& s, const std::wstring& pattern, const std::wstring& replacement)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while (pos != s.npos)
|
||||
{
|
||||
pos = s.find(pattern, pos);
|
||||
if (pos != s.npos)
|
||||
{
|
||||
s.replace(pos, pattern.length(), replacement);
|
||||
pos += replacement.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XMB reading:
|
||||
|
||||
static XMLElement* ParseNode(InputStream& stream, XMBFile* file, const std::vector<utf16string>& ElementNames, const std::vector<utf16string>& AttributeNames)
|
||||
{
|
||||
READARRAY(char, 2, Head); CHECK(strncmp(Head, "XN", 2) == 0, NULL);
|
||||
READ(int32_t, Length);
|
||||
|
||||
XMLElement* node = new XMLElement;
|
||||
|
||||
node->text = ReadUString(stream);
|
||||
|
||||
READ(int32_t, Name);
|
||||
node->name = ElementNames[Name];
|
||||
|
||||
if (file->format == XMBFile::AOE3)
|
||||
{
|
||||
READ(int32_t, LineNumber);
|
||||
node->linenum = LineNumber;
|
||||
}
|
||||
|
||||
READ(int32_t, NumAttributes);
|
||||
node->attrs.reserve(NumAttributes);
|
||||
for (int32_t i = 0; i < NumAttributes; ++i)
|
||||
{
|
||||
READ(int32_t, AttrID);
|
||||
|
||||
XMLAttribute attr;
|
||||
attr.name = AttributeNames[AttrID];
|
||||
attr.value = ReadUString(stream);
|
||||
node->attrs.push_back(attr);
|
||||
}
|
||||
|
||||
READ(int32_t, NumChildren);
|
||||
node->childs.reserve(NumChildren);
|
||||
for (int32_t i = 0; i < NumChildren; ++i)
|
||||
{
|
||||
XMLElement* child = ParseNode(stream, file, ElementNames, AttributeNames);
|
||||
if (! child)
|
||||
{
|
||||
DeallocateElement(node);
|
||||
return NULL;
|
||||
}
|
||||
node->childs.push_back(child);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool ParseXMB(InputStream& stream, XMBFile* file)
|
||||
{
|
||||
READARRAY(char, 2, Header); CHECK(strncmp(Header, "X1", 2) == 0, false);
|
||||
READ(int32_t, DataLength);
|
||||
READARRAY(char, 2, RootHeader); CHECK(strncmp(RootHeader, "XR", 2) == 0, false);
|
||||
READARRAY(int32_t, 2, Unknown);
|
||||
|
||||
CHECK(Unknown[0] == 4, false);
|
||||
|
||||
if (Unknown[1] == 7)
|
||||
file->format = XMBFile::AOM;
|
||||
else if (Unknown[1] == 8)
|
||||
file->format = XMBFile::AOE3;
|
||||
else
|
||||
{
|
||||
// wxLogWarning(_("Unrecognised XMB format - assuming AoE3"));
|
||||
assert(! "Unrecognised format");
|
||||
file->format = XMBFile::AOE3;
|
||||
}
|
||||
|
||||
std::vector<utf16string> ElementNames;
|
||||
READ(int, NumElements);
|
||||
ElementNames.reserve(NumElements);
|
||||
for (int i = 0; i < NumElements; ++i)
|
||||
ElementNames.push_back(ReadUString(stream));
|
||||
|
||||
std::vector<utf16string> AttributeNames;
|
||||
READ(int, NumAttributes);
|
||||
AttributeNames.reserve(NumAttributes);
|
||||
for (int i = 0; i < NumAttributes; ++i)
|
||||
AttributeNames.push_back(ReadUString(stream));
|
||||
|
||||
XMLElement* root = ParseNode(stream, file, ElementNames, AttributeNames);
|
||||
if (! root)
|
||||
return false;
|
||||
|
||||
file->root = root;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
XMBFile* XMBFile::LoadFromXMB(InputStream& stream)
|
||||
{
|
||||
XMBFile* file = new XMBFile();
|
||||
|
||||
if (! ParseXMB(stream, file))
|
||||
{
|
||||
delete file;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XMB writing:
|
||||
|
||||
|
||||
typedef std::map<utf16string, uint32_t> StringTable;
|
||||
|
||||
static void ExtractStrings(XMLElement* node, StringTable& elements, StringTable& attributes)
|
||||
{
|
||||
if (elements.find(node->name) == elements.end())
|
||||
elements.insert(std::make_pair(node->name, (uint32_t)elements.size()));
|
||||
|
||||
for (size_t i = 0; i < node->attrs.size(); ++i)
|
||||
if (attributes.find(node->attrs[i].name) == attributes.end())
|
||||
attributes.insert(std::make_pair(node->attrs[i].name, (uint32_t)attributes.size()));
|
||||
|
||||
for (size_t i = 0; i < node->childs.size(); ++i)
|
||||
ExtractStrings(node->childs[i], elements, attributes);
|
||||
}
|
||||
|
||||
|
||||
static void WriteNode(SeekableOutputStream& stream, XMBFile* file, XMLElement* node, const StringTable& elements, const StringTable& attributes)
|
||||
{
|
||||
stream.Write("XN", 2);
|
||||
|
||||
off_t Length_off = stream.Tell();
|
||||
stream.Write("????", 4);
|
||||
|
||||
WriteUString(stream, node->text);
|
||||
|
||||
uint32_t Name = elements.find(node->name)->second;
|
||||
stream.Write(&Name, 4);
|
||||
|
||||
if (file->format == XMBFile::AOE3)
|
||||
{
|
||||
int32_t lineNum = node->linenum;
|
||||
stream.Write(&lineNum, 4);
|
||||
}
|
||||
|
||||
uint32_t NumAttributes = (uint32_t)node->attrs.size();
|
||||
stream.Write(&NumAttributes, 4);
|
||||
for (uint32_t i = 0; i < NumAttributes; ++i)
|
||||
{
|
||||
uint32_t n = attributes.find(node->attrs[i].name)->second;
|
||||
stream.Write(&n, 4);
|
||||
WriteUString(stream, node->attrs[i].value);
|
||||
}
|
||||
|
||||
uint32_t NumChildren = (uint32_t)node->childs.size();
|
||||
stream.Write(&NumChildren, 4);
|
||||
for (uint32_t i = 0; i < NumChildren; ++i)
|
||||
WriteNode(stream, file, node->childs[i], elements, attributes);
|
||||
|
||||
off_t NodeEnd = stream.Tell();
|
||||
stream.Seek(Length_off, Stream::FROM_START);
|
||||
int Length = NodeEnd - (Length_off+4);
|
||||
stream.Write(&Length, 4);
|
||||
stream.Seek(NodeEnd, Stream::FROM_START);
|
||||
}
|
||||
|
||||
void XMBFile::SaveAsXMB(SeekableOutputStream& stream)
|
||||
{
|
||||
stream.Write("X1", 2);
|
||||
|
||||
off_t Length_off = stream.Tell();
|
||||
stream.Write("????", 4);
|
||||
|
||||
stream.Write("XR", 2);
|
||||
|
||||
int version[2] = { 4, -1 };
|
||||
if (format == XMBFile::AOM)
|
||||
version[1] = 7;
|
||||
else if (format == XMBFile::AOE3)
|
||||
version[1] = 8;
|
||||
else
|
||||
{
|
||||
// wxLogWarning(_("Unknown XMB format - assuming AoE3"));
|
||||
format = XMBFile::AOE3;
|
||||
version[1] = 8;
|
||||
}
|
||||
stream.Write(version, 8);
|
||||
|
||||
// Get the list of element/attribute names, sorted by first appearance
|
||||
StringTable ElementNames;
|
||||
StringTable AttributeNames;
|
||||
ExtractStrings(root, ElementNames, AttributeNames);
|
||||
|
||||
|
||||
// Convert into handy vector format for outputting
|
||||
std::vector<utf16string> ElementNamesByID;
|
||||
ElementNamesByID.resize(ElementNames.size());
|
||||
for (StringTable::iterator it = ElementNames.begin(); it != ElementNames.end(); ++it)
|
||||
ElementNamesByID[it->second] = it->first;
|
||||
|
||||
// Output element names
|
||||
uint32_t NumElements = (uint32_t)ElementNamesByID.size();
|
||||
stream.Write(&NumElements, 4);
|
||||
for (uint32_t i = 0; i < NumElements; ++i)
|
||||
WriteUString(stream, ElementNamesByID[i]);
|
||||
|
||||
|
||||
// Convert into handy vector format for outputting
|
||||
std::vector<utf16string> AttributeNamesByID;
|
||||
AttributeNamesByID.resize(AttributeNames.size());
|
||||
for (StringTable::iterator it = AttributeNames.begin(); it != AttributeNames.end(); ++it)
|
||||
AttributeNamesByID[it->second] = it->first;
|
||||
|
||||
// Output attribute names
|
||||
uint32_t NumAttributes = (uint32_t)AttributeNamesByID.size();
|
||||
stream.Write(&NumAttributes, 4);
|
||||
for (uint32_t i = 0; i < NumAttributes; ++i)
|
||||
WriteUString(stream, AttributeNamesByID[i]);
|
||||
|
||||
// Output root node, plus all descendants
|
||||
WriteNode(stream, this, root, ElementNames, AttributeNames);
|
||||
|
||||
// Fill in data-length field near the beginning
|
||||
off_t DataEnd = stream.Tell();
|
||||
stream.Seek(Length_off, Stream::FROM_START);
|
||||
int Length = DataEnd - (Length_off+4);
|
||||
stream.Write(&Length, 4);
|
||||
stream.Seek(DataEnd, Stream::FROM_START);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XML writing:
|
||||
|
||||
const wchar_t* in = L"\t";
|
||||
void OutputNode(std::wstring& output, const XMLElement* node, const std::wstring& indent)
|
||||
{
|
||||
// Build up strings using lots of += instead of +, because it gives
|
||||
// a significant (>30%) performance increase.
|
||||
output += L"\n";
|
||||
output += indent;
|
||||
output += L"<";
|
||||
output += utf16tow(node->name);
|
||||
|
||||
for (size_t i = 0; i < node->attrs.size(); ++i)
|
||||
{
|
||||
std::wstring value = utf16tow(node->attrs[i].value);
|
||||
// Escape funny characters
|
||||
if (value.find_first_of(L"&<>\"") != value.npos)
|
||||
{
|
||||
StringReplace(value, L"&", L"&");
|
||||
StringReplace(value, L"<", L"<");
|
||||
StringReplace(value, L">", L">");
|
||||
StringReplace(value, L"\"", L""");
|
||||
}
|
||||
|
||||
output += L" ";
|
||||
output += utf16tow(node->attrs[i].name);
|
||||
output += L"=\"";
|
||||
output += value;
|
||||
output += L"\"";
|
||||
}
|
||||
|
||||
// Output the element's contents, in an attemptedly nice readable format:
|
||||
|
||||
std::wstring name = utf16tow(node->name);
|
||||
if (node->text.length())
|
||||
{
|
||||
std::wstring text = utf16tow(node->text);
|
||||
|
||||
// Wrap text in CDATA when necessary. (Maybe we should use < etc
|
||||
// in some cases?)
|
||||
if (text.find_first_of(L"<>&") != text.npos)
|
||||
{
|
||||
// (According to the XML spec, ">" is allowed in non-CDATA non-escaped
|
||||
// content, but we avoid that because it's confusing.)
|
||||
|
||||
StringReplace(text, L"]]>", L"]]>]]><![CDATA["); // paranoia
|
||||
|
||||
std::wstring newtext = L"<![CDATA[\n";
|
||||
newtext += indent;
|
||||
newtext += in;
|
||||
newtext += text;
|
||||
newtext += L"\n"; // (All this extra whitespace will be trimmed during XML->XMB)
|
||||
newtext += indent;
|
||||
newtext += L"]]>";
|
||||
std::swap(newtext, text);
|
||||
}
|
||||
|
||||
if (node->childs.size())
|
||||
{
|
||||
/* <el>
|
||||
Text
|
||||
<child>...
|
||||
</el> */
|
||||
output += L">\n";
|
||||
output += indent;
|
||||
output += in;
|
||||
output += text;
|
||||
std::wstring nextIndent = indent + in;
|
||||
for (size_t i = 0; i < node->childs.size(); ++i)
|
||||
OutputNode(output, node->childs[i], nextIndent);
|
||||
output += L"\n";
|
||||
output += indent;
|
||||
output += L"</";
|
||||
output += name;
|
||||
output += L">";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* <el>Text</el> */
|
||||
output += L">";
|
||||
output += text;
|
||||
output += L"</";
|
||||
output += name;
|
||||
output += L">";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->childs.size())
|
||||
{
|
||||
/* <el>
|
||||
<child>...
|
||||
</el> */
|
||||
output += L">";
|
||||
std::wstring nextIndent = indent + in;
|
||||
for (size_t i = 0; i < node->childs.size(); ++i)
|
||||
OutputNode(output, node->childs[i], nextIndent);
|
||||
output += L"\n";
|
||||
output += indent;
|
||||
output += L"</";
|
||||
output += name;
|
||||
output += L">";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* <el/> */
|
||||
output += L"/>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring XMBFile::SaveAsXML()
|
||||
{
|
||||
std::wstring output;
|
||||
OutputNode(output, root, L"");
|
||||
return output;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XML reading:
|
||||
|
||||
class XeroHandler : public DefaultHandler
|
||||
{
|
||||
public:
|
||||
XeroHandler() : Root(NULL), m_locator(NULL) {}
|
||||
~XeroHandler() { if (Root) DeallocateElement(Root); }
|
||||
|
||||
// SAX2 event handlers:
|
||||
virtual void startDocument();
|
||||
virtual void endDocument();
|
||||
virtual void startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const Attributes& attrs);
|
||||
virtual void endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname);
|
||||
virtual void characters(const XMLCh* const chars, const unsigned int length);
|
||||
|
||||
// Locator, for determining line numbers of elements
|
||||
const Locator* m_locator;
|
||||
virtual void setDocumentLocator(const Locator* const locator) {
|
||||
m_locator = locator;
|
||||
}
|
||||
|
||||
// Return and remove the root element from this object (so it won't get deleted)
|
||||
XMLElement* ReleaseRoot() { XMLElement* t = Root; Root = NULL; return t; }
|
||||
|
||||
private:
|
||||
XMLElement* Root;
|
||||
std::stack<XMLElement*> ElementStack; // so the event handlers can be aware of the current element
|
||||
};
|
||||
|
||||
|
||||
class XeroErrorHandler : public ErrorHandler
|
||||
{
|
||||
public:
|
||||
XeroErrorHandler() : sawErrors(false) {}
|
||||
~XeroErrorHandler() {}
|
||||
void warning(const SAXParseException& err) { complain(err, L"warning"); }
|
||||
void error(const SAXParseException& err) { complain(err, L"error"); }
|
||||
void fatalError(const SAXParseException& err) { complain(err, L"fatal error"); };
|
||||
void resetErrors() { sawErrors = false; }
|
||||
bool getSawErrors() const { return sawErrors; }
|
||||
utf16string getErrorText() { return errorText; }
|
||||
private:
|
||||
bool sawErrors;
|
||||
utf16string errorText;
|
||||
void complain(const SAXParseException& err, const wchar_t* severity) {
|
||||
sawErrors = true;
|
||||
C_ASSERT(sizeof(utf16_t) == sizeof(XMLCh));
|
||||
errorText += wtoutf16(L"XML ");
|
||||
errorText += wtoutf16(severity);
|
||||
errorText += wtoutf16(L": ");
|
||||
errorText += (utf16_t*)err.getSystemId();
|
||||
errorText += wtoutf16(L" / ");
|
||||
errorText += (utf16_t*)err.getMessage();
|
||||
}
|
||||
};
|
||||
|
||||
class XeroBinInputStream : public BinInputStream
|
||||
{
|
||||
public:
|
||||
XeroBinInputStream(InputStream& stream) : m_stream(stream) {}
|
||||
virtual XMLFilePos curPos () const
|
||||
{
|
||||
return m_stream.Tell();
|
||||
}
|
||||
virtual XMLSize_t readBytes (XMLByte *const toFill, const XMLSize_t maxToRead)
|
||||
{
|
||||
return (unsigned int)m_stream.Read(toFill, (unsigned int)maxToRead);
|
||||
}
|
||||
virtual const XMLCh* getContentType() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
private:
|
||||
InputStream& m_stream;
|
||||
};
|
||||
|
||||
class XeroInputSource : public InputSource
|
||||
{
|
||||
public:
|
||||
XeroInputSource(InputStream& stream) : m_stream(stream) {}
|
||||
virtual BinInputStream *makeStream() const
|
||||
{
|
||||
return new XeroBinInputStream(m_stream);
|
||||
}
|
||||
private:
|
||||
InputStream& m_stream;
|
||||
};
|
||||
|
||||
|
||||
XMBFile* DatafileIO::XMLReader::LoadFromXML(InputStream& stream)
|
||||
{
|
||||
XMBFile* ret = new XMBFile();
|
||||
|
||||
// I don't like Xerces :-(
|
||||
|
||||
SAX2XMLReader* Parser = XMLReaderFactory::createXMLReader();
|
||||
|
||||
// DTD validation:
|
||||
// Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
|
||||
// Parser->setFeature(XMLUni::fgXercesDynamic, true);
|
||||
|
||||
XeroHandler handler;
|
||||
Parser->setContentHandler(&handler);
|
||||
|
||||
XeroErrorHandler errorHandler;
|
||||
Parser->setErrorHandler(&errorHandler);
|
||||
|
||||
|
||||
// Build the XMLElement tree inside the XeroHandler
|
||||
XeroInputSource src(stream);
|
||||
Parser->parse(src);
|
||||
|
||||
delete Parser;
|
||||
|
||||
if (errorHandler.getSawErrors())
|
||||
{
|
||||
//wxLogError(_("Error in XML file %s"), filename);
|
||||
// TODO URGENT: report errors
|
||||
delete ret;
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
XMLElement* root = handler.ReleaseRoot();
|
||||
ret->root = root->childs[0];
|
||||
delete root;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void XeroHandler::startDocument()
|
||||
{
|
||||
Root = new XMLElement;
|
||||
ElementStack.push(Root);
|
||||
}
|
||||
|
||||
void XeroHandler::endDocument()
|
||||
{
|
||||
}
|
||||
|
||||
void XeroHandler::startElement(const XMLCh* const /*uri*/, const XMLCh* const localname, const XMLCh* const /*qname*/, const Attributes& attrs)
|
||||
{
|
||||
utf16string elementName = (utf16_t*)localname;
|
||||
|
||||
// Create a new element
|
||||
XMLElement* e = new XMLElement;
|
||||
e->name = elementName;
|
||||
e->linenum = m_locator->getLineNumber();
|
||||
|
||||
// Store all the attributes in the new element
|
||||
for (unsigned int i = 0; i < attrs.getLength(); ++i)
|
||||
{
|
||||
utf16string attrName = (utf16_t*)attrs.getLocalName(i);
|
||||
XMLAttribute attr;
|
||||
attr.name = attrName;
|
||||
attr.value = (utf16_t*)attrs.getValue(i);
|
||||
e->attrs.push_back(attr);
|
||||
}
|
||||
|
||||
// Add the element to its parent
|
||||
ElementStack.top()->childs.push_back(e);
|
||||
|
||||
// Set as parent of following elements
|
||||
ElementStack.push(e);
|
||||
}
|
||||
|
||||
void XeroHandler::endElement(const XMLCh* const /*uri*/, const XMLCh* const /*localname*/, const XMLCh* const /*qname*/)
|
||||
{
|
||||
// Trim whitespace around the element's contents
|
||||
|
||||
std::string whitespaceA = " \t\r\n";
|
||||
utf16string whitespace (whitespaceA.begin(), whitespaceA.end());
|
||||
|
||||
XMLElement* el = ElementStack.top();
|
||||
// Find the start of the non-whitespace section
|
||||
size_t first = el->text.find_first_not_of(whitespace);
|
||||
|
||||
if (first == el->text.npos)
|
||||
// Entirely whitespace - easy to handle
|
||||
el->text = utf16string();
|
||||
|
||||
else
|
||||
{
|
||||
// Count the number of \n being cut off,
|
||||
// and add them to the line number
|
||||
// utf16string trimmed (el->text.begin(), el->text.begin()+first);
|
||||
// el->linenum += (int)std::count(trimmed.begin(), trimmed.end(), (utf16_t)'\n');
|
||||
// (Only use this when the line number should point to the start of the
|
||||
// content, rather than the element tag. TODO: enable it in that situation.)
|
||||
|
||||
// Find the end of the non-whitespace section,
|
||||
// and trim off everything else
|
||||
size_t last = el->text.find_last_not_of(whitespace);
|
||||
el->text = el->text.substr(first, 1+last-first);
|
||||
}
|
||||
|
||||
ElementStack.pop();
|
||||
}
|
||||
|
||||
void XeroHandler::characters(const XMLCh* const chars, const unsigned int length)
|
||||
{
|
||||
ElementStack.top()->text += utf16string((utf16_t*)chars, length);
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../Util.h"
|
||||
|
||||
namespace DatafileIO
|
||||
{
|
||||
class InputStream;
|
||||
class SeekableOutputStream;
|
||||
|
||||
// Convenient storage for the internal tree
|
||||
struct XMLAttribute {
|
||||
utf16string name;
|
||||
utf16string value;
|
||||
};
|
||||
|
||||
struct XMLElement {
|
||||
utf16string name;
|
||||
int linenum;
|
||||
utf16string text;
|
||||
std::vector<XMLElement*> childs;
|
||||
std::vector<XMLAttribute> attrs;
|
||||
};
|
||||
|
||||
struct XMBFile;
|
||||
|
||||
// Enforces initialisation/termination the XML system
|
||||
struct XMLReader {
|
||||
XMLReader();
|
||||
~XMLReader();
|
||||
|
||||
XMBFile* LoadFromXML(InputStream& stream);
|
||||
};
|
||||
|
||||
struct XMBFile {
|
||||
XMLElement* root;
|
||||
enum { UNKNOWN, AOM, AOE3 } format;
|
||||
|
||||
XMBFile();
|
||||
~XMBFile();
|
||||
|
||||
// This does *not* understand l33t-compressed data. Please
|
||||
// decompress them first.
|
||||
static XMBFile* LoadFromXMB(InputStream& stream);
|
||||
|
||||
// Caller should convert the returned data to some encoding, and
|
||||
// prepend "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" (or whatever
|
||||
// is appropriate for that encoding)
|
||||
std::wstring SaveAsXML();
|
||||
|
||||
void SaveAsXMB(SeekableOutputStream& stream);
|
||||
};
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
@ -1,37 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Precompiled headers:
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _SCL_SECURE_NO_DEPRECATE // shut up, std::copy isn't deprecated
|
||||
#endif
|
||||
|
||||
#ifdef USING_PCH
|
||||
|
||||
// Exclude rarely-used stuff from Windows headers
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
#endif // USING_PCH
|
Loading…
Reference in New Issue
Block a user