--- /dev/null
+cmake_minimum_required (VERSION 2.8.8)
+project (QTinns)
+set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/")
+
+# needed packages
+find_package (Qt5Core)
+find_package (Qt5Widgets)
+find_package (Qt5Network)
+find_package (Qt5LinguistTools)
+find_package (ZLIB REQUIRED)
+find_package (Irrlicht REQUIRED)
+
+# includes and outputs
+set (CMAKE_INCLUDE_CURRENT_DIR on)
+include_directories (${PROJECT_SOURCE_DIR})
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
+
+# compiler settings
+set (CMAKE_CXX_FLAGS "-std=c++11 -W -Wall -Wextra -Os")
+set (CMAKE_C_FLAGS "-std=c++11 -W -Wall -Wextra -Os")
+
+#add_subdirectory (analyzer)
+add_subdirectory (editor)
+add_subdirectory (filesystem)
+#add_subdirectory (renderer)
+#add_subdirectory (server)
+add_subdirectory (tests)
+add_subdirectory (tools)
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+This directory contains QTinNS, a Qt based reimplementation of TinNS
+and corresponding tools, a Neocron server emulation.
+
+QTinNS is free software. See the files whose names start with COPYING
+for copying permission.
+
+Copyright (C) 2013 Akiko <akiko@linux-addicted.net>.
--- /dev/null
+#!/bin/sh
+
+rm -rf CMakeCache.txt
+rm -rf CMakeFiles/
+rm -rf Makefile
+rm -rf cmake_install.cmake
+rm -rf *.qrc.depends
+rm -rf moc_*.*
+
+rm -rf analyzer/CMakeCache.txt
+rm -rf analyzer/CMakeFiles/
+rm -rf analyzer/Makefile
+rm -rf analyzer/cmake_install.cmake
+rm -rf analyzer/*.qrc.depends
+rm -rf analyzer/moc_*.*
+
+rm -rf editor/CMakeCache.txt
+rm -rf editor/CMakeFiles/
+rm -rf editor/Makefile
+rm -rf editor/cmake_install.cmake
+rm -rf editor/*.qrc.depends
+rm -rf editor/moc_*.*
+
+rm -rf filesystem/CMakeCache.txt
+rm -rf filesystem/CMakeFiles/
+rm -rf filesystem/Makefile
+rm -rf filesystem/cmake_install.cmake
+rm -rf filesystem/*.qrc.depends
+rm -rf filesystem/moc_*.*
+
+rm -rf renderer/CMakeCache.txt
+rm -rf renderer/CMakeFiles/
+rm -rf renderer/Makefile
+rm -rf renderer/cmake_install.cmake
+rm -rf renderer/*.qrc.depends
+rm -rf renderer/moc_*.*
+
+rm -rf server/CMakeCache.txt
+rm -rf server/CMakeFiles/
+rm -rf server/Makefile
+rm -rf server/cmake_install.cmake
+rm -rf server/*.qrc.depends
+rm -rf server/moc_*.*
+
+rm -rf tests/CMakeCache.txt
+rm -rf tests/CMakeFiles/
+rm -rf tests/Makefile
+rm -rf tests/cmake_install.cmake
+rm -rf tests/*.qrc.depends
+rm -rf tests/moc_*.*
+
+rm -rf tools/CMakeCache.txt
+rm -rf tools/CMakeFiles/
+rm -rf tools/Makefile
+rm -rf tools/cmake_install.cmake
+rm -rf tools/*.qrc.depends
+rm -rf tools/moc_*.*
+
+# code counter
+LOG="/tmp/log.$$"
+LINES=0
+C=0
+
+find| grep "\.c$" >$LOG
+find| grep "\.cpp$" >>$LOG
+find| grep "\.cxx$" >>$LOG
+find| grep "\.h$" >>$LOG
+find| grep "\.hpp$" >>$LOG
+find| grep "\.hxx$" >>$LOG
+find| grep "\.sh$" >>$LOG
+find| grep "\.S$" >>$LOG
+find| grep "\.ts$" >>$LOG
+find| grep "\.ui$" >>$LOG
+find| grep "\.qrc$" >>$LOG
+find| grep "\.cmake$" >>$LOG
+while read L
+do
+ C=$((C+1))
+ W=$(cat $L|wc -l)
+ S=$(cat $L|wc -c)
+ SIZE=$((SIZE+S))
+ LINES=$((LINES+W))
+done <$LOG
+rm $LOG
+
+echo
+echo "--- REPOSITORY SUMMARY ---"
+echo "source files: $C"
+echo "lines of code: $LINES"
+echo "size of code: $SIZE bytes"
+echo
--- /dev/null
+set (IRRLICHT_FOUND TRUE)
+
+find_path (
+ IRRLICHT_INCLUDE_DIRS
+ NAMES
+ irrlicht.h
+ HINTS
+ ENV
+ IRRLICHT_ROOT
+ PATHS
+ /usr
+ /usr/local
+ PATH_SUFFIXES
+ include
+ irrlicht
+)
+
+find_library (
+ IRRLICHT_LIBRARY
+ Irrlicht
+ HINTS
+ ENV
+ IRRLICHT_ROOT
+ PATHS
+ /usr/lib
+ /usr/local/lib
+)
+
+if (IRRLICHT_INCLUDE_DIRS AND EXISTS "${IRRLICHT_INCLUDE_DIRS}/IrrCompileConfig.h")
+ file (STRINGS "${IRRLICHT_INCLUDE_DIRS}/IrrCompileConfig.h"
+ verstr REGEX "^#define[ \t]+IRRLICHT_SDK_VERSION[ \t]+\".+\""
+ )
+ string (REGEX REPLACE "^#define[ \t]+IRRLICHT_SDK_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+ IRRLICHT_VERSION_STRING "${verstr}"
+ )
+ unset (verstr)
+endif ()
+
+include (FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS (Irrlicht REQUIRED_VARS IRRLICHT_LIBRARY IRRLICHT_INCLUDE_DIRS VERSION_VAR IRRLICHT_VERSION_STRING)
+
+mark_as_advanced (IRRLICHT_INCLUDE_DIRS IRRLICHT_LIBRARIES)
--- /dev/null
+#pragma once
+
+#include <limits>
+#include <QObject>
+
+namespace NC
+{
+ namespace Meta
+ {
+ const quint32 Error = std::numeric_limits<quint32>::max();
+
+ enum Type : quint64 {
+ T00 = 0x0,
+ T01 = 0x1,
+ T02 = 0x2,
+ T03 = 0x4,
+ T04 = 0x8,
+ T05 = 0x10,
+ T06 = 0x20,
+ T07 = 0x40,
+ T08 = 0x80,
+ T09 = 0x100,
+ T10 = 0x200,
+ T11 = 0x400,
+ T12 = 0x800,
+ T13 = 0x1000,
+ T14 = 0x2000,
+ T15 = 0x4000,
+ T16 = 0x8000,
+ T17 = 0x10000,
+ T18 = 0x20000,
+ T19 = 0x40000,
+ T20 = 0x80000,
+ T21 = 0x100000,
+ T22 = 0x200000,
+ T23 = 0x400000,
+ T24 = 0x800000,
+ T25 = 0x1000000,
+ T26 = 0x2000000,
+ T27 = 0x4000000,
+ T28 = 0x8000000,
+ T29 = 0x10000000,
+ T30 = 0x20000000,
+ T31 = 0x40000000,
+ T32 = 0x80000000,
+ T33 = 0x100000000,
+ T34 = 0x200000000,
+ T35 = 0x400000000,
+ T36 = 0x800000000,
+ T37 = 0x1000000000,
+ T38 = 0x2000000000,
+ T39 = 0x4000000000,
+ T40 = 0x8000000000
+ };
+ }
+
+ namespace FileData
+ {
+ enum Type : quint8 {
+ None = Meta::Type::T00,
+ HSize = Meta::Type::T01,
+ Position = Meta::Type::T02,
+ CSize = Meta::Type::T03,
+ OSize = Meta::Type::T04,
+ NameLength = Meta::Type::T05,
+ Name = Meta::Type::T06,
+ CData = Meta::Type::T07,
+ OData = Meta::Type::T08,
+ All = HSize + Position + CSize + OSize + NameLength + Name + CData + OData
+ };
+ }
+
+ namespace Identify
+ {
+ enum Type : quint32 {
+ Error = Meta::Error,
+ Plain = Error - 1,
+ ZLIB = Error - 2,
+ VFS = 0x3D458CDE,
+ PAK1 = 0x883DF70A,
+ PAK2 = 0x93847584,
+ PAK3 = 0xABFDEFBD
+ };
+ }
+}
--- /dev/null
+# Qt sources
+set (E_SOURCES Main.cxx MainWindow.cxx)
+set (E_HEADERS MainWindow.hxx)
+set (E_UI_FILES MainWindow.ui)
+set (E_RES_FILES Resources.qrc)
+set (E_TS_FILES i18n_english.ts i18n_french.ts i18n_german.ts)
+
+# wrappers
+QT5_ADD_TRANSLATION (E_TS_SOURCES ${E_TS_FILES})
+QT5_WRAP_CPP (E_MOC_SOURCES ${E_HEADERS})
+QT5_WRAP_UI (E_UI_SOURCES ${E_UI_FILES})
+QT5_ADD_RESOURCES (E_RES_SOURCES ${E_RES_FILES})
+
+# apps
+add_executable (QTinNS_Editor ${E_SOURCES} ${E_MOC_SOURCES} ${E_UI_SOURCES} ${E_RES_SOURCES} ${E_TS_SOURCES})
+qt5_use_modules (QTinNS_Editor Core Widgets)
+target_link_libraries (QTinNS_Editor Filesystem)
--- /dev/null
+#include <QApplication>
+#include "MainWindow.hxx"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow w;
+
+ w.show();
+
+ return app.exec();
+}
--- /dev/null
+#include <QApplication>
+#include <QCryptographicHash>
+#include <QDebug>
+#include <QEvent>
+#include <QFileDialog>
+#include <QProxyStyle>
+#include <QSettings>
+#include <QStyleFactory>
+#include <QTranslator>
+#include "MainWindow.hxx"
+#include "ui_MainWindow.h"
+#include "filesystem/NCFilesystem.hxx"
+
+// --- internal typedefs ---
+
+using QTW = QTableWidget;
+using QTWI = QTableWidgetItem;
+using QCH = QCryptographicHash;
+using ColType = NC::FileData::Type;
+using FileType = NC::Identify::Type;
+
+// --- internal constants ---
+
+const QColor Green(180, 255, 180);
+const QColor Grey(180, 180, 180);
+const QColor Red(255, 180, 180);
+const QString TableHeader("header size;position;compressed size;original size;name length;name;SHA-1");
+
+// --- constructors and deconstructors ---
+
+MainWindow::MainWindow(QWidget *parent)
+: QMainWindow(parent), _ui(new Ui::MainWindow), _translator(new QTranslator(this)),
+ _settings(new QSettings("LinuxAddicted", "QTinNS Editor", this)), _vfs(new NCFilesystem)
+{
+ _ui->setupUi(this);
+ _ui->wid_table->setColumnCount(7);
+ _ui->wid_table->setHorizontalHeaderLabels(TableHeader.split(";"));
+ _ui->wid_table->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ setLanguage(Language::English);
+ setupActions();
+
+ if (_settings)
+ {
+ move(_settings->value("mw_position", QPoint(40, 40)).toPoint());
+ resize(_settings->value("mw_size", QSize(800, 600)).toSize());
+ setMinimumSize(_settings->value("mw_minsize", QSize(640, 480)).toSize());
+ }
+ else
+ {
+ move(40, 40);
+ resize(800, 600);
+ setMinimumSize(640, 480);
+ }
+
+ slotStatusUpdate();
+ setMode(Mode::Fresh);
+}
+
+MainWindow::~MainWindow()
+{
+ if (_settings)
+ {
+ _settings->setValue("mw_position", pos());
+ _settings->setValue("mw_size", size());
+ _settings->setValue("mw_minsize", minimumSize());
+ _settings->sync();
+ }
+
+ delete _vfs;
+ delete _settings;
+ delete _translator;
+ delete _ui;
+}
+
+// --- slots ---
+
+void MainWindow::slotAppNew()
+{
+ _vfs->clear();
+ setMode(Mode::Fresh);
+}
+
+void MainWindow::slotAppOpen()
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("DIA-OPEN-VFS"), "./", tr("FLT-FILE-VFS"));
+
+ if (_vfs->load(filename) != _vfs->Error)
+ {
+ _filename = filename;
+ slotStatusUpdate();
+ setMode(Mode::Edited);
+ }
+}
+
+void MainWindow::slotAppSave()
+{
+ if (_filename.isEmpty())
+ slotAppSaveAs();
+ else
+ _vfs->save(_filename);
+}
+
+void MainWindow::slotAppSaveAs()
+{
+ QString filename = QFileDialog::getSaveFileName(this, tr("DIA-SAVE-VFS"), "./unnamed.pak", tr("FLT-FILE-VFS"));
+
+ if (filename.size())
+ {
+ _filename = filename;
+ _vfs->save(_filename);
+ }
+}
+
+void MainWindow::slotAppQuit()
+{
+ close();
+}
+
+void MainWindow::slotFileAdd()
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("DIA-OPEN-FILE"), "./", tr("FLT-FILE-ANY"));
+
+ if (filename.size())
+ {
+ _vfs->fileAdd(filename);
+ slotStatusUpdate();
+ }
+}
+
+void MainWindow::slotFileReplace()
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("DIA-OPEN-FILE"), "./", tr("FLT-FILE-ANY"));
+
+ if (filename.size())
+ {
+ _vfs->fileReplace(filename, _ui->wid_table->currentRow());
+ slotStatusUpdate();
+ }
+}
+
+void MainWindow::slotFileRemove()
+{
+ _vfs->fileRemove(_ui->wid_table->currentRow());
+ slotStatusUpdate();
+ setMode(Mode::Edited);
+}
+
+void MainWindow::slotFileSavePlain()
+{
+ QString filename = QFileDialog::getSaveFileName(this, tr("DIA-SAVE-PLAIN"), "./file", tr("FLT-FILE-PLAIN"));
+
+ if (filename.size())
+ _vfs->fileSave(filename, _ui->wid_table->currentRow());
+}
+
+void MainWindow::slotFileSavePAK()
+{
+ QString filename = QFileDialog::getSaveFileName(this, tr("DIA-SAVE-PAK"), "./file", tr("FLT-FILE-PAK"));
+
+ if (filename.size())
+ _vfs->fileSave(filename, _ui->wid_table->currentRow(), FileType::PAK1);
+}
+
+void MainWindow::slotFileSaveZLIB()
+{
+ QString filename = QFileDialog::getSaveFileName(this, tr("DIA-SAVE-ZLIB"), "./file", tr("FLT-FILE-ZLIB"));
+
+ if (filename.size())
+ _vfs->fileSave(filename, _ui->wid_table->currentRow(), FileType::ZLIB);
+}
+
+void MainWindow::slotFileConvWin()
+{
+ QTW *table = _ui->wid_table;
+ NCFile entry = _vfs->fileGet(table->currentRow());
+
+ entry.setName(entry.name().replace("/", "\\"));
+ _vfs->fileReplace(entry, table->currentRow());
+ slotTableSelected();
+}
+
+void MainWindow::slotFileConvLin()
+{
+ QTW *table = _ui->wid_table;
+ NCFile entry = _vfs->fileGet(table->currentRow());
+
+ entry.setName(entry.name().replace("\\", "/"));
+ _vfs->fileReplace(entry, table->currentRow());
+ slotTableSelected();
+}
+
+void MainWindow::slotLangEnglish()
+{
+ setLanguage(Language::English);
+}
+
+void MainWindow::slotLangFrench()
+{
+ setLanguage(Language::French);
+}
+
+void MainWindow::slotLangGerman()
+{
+ setLanguage(Language::German);
+}
+
+void MainWindow::slotStyleDefault()
+{
+ QApplication::setStyle(new QProxyStyle);
+}
+
+void MainWindow::slotStyleFusion()
+{
+ QApplication::setStyle(QStyleFactory::create("Fusion"));
+}
+
+void MainWindow::slotStyleWindows()
+{
+ QApplication::setStyle(QStyleFactory::create("Windows"));
+}
+
+void MainWindow::slotStyleGTK()
+{
+ QApplication::setStyle(QStyleFactory::create("GTK+"));
+}
+
+void MainWindow::slotAboutApp()
+{
+}
+
+void MainWindow::slotAboutQt()
+{
+ qApp->aboutQt();
+}
+
+void MainWindow::slotStatusUpdate()
+{
+ QString msg1 = tr("MSG-UPD-FILE") + ": '" + _filename + "' " + tr("MSG-UPD-WITH") + " "
+ + QString::number(_vfs->count()) + " " + tr("MSG-UPD-ENTRIES");
+ QString msg2 = tr("FRM-MAINWINDOW") + " - " + msg1;
+
+ statusBar()->showMessage(msg1);
+ setWindowTitle(msg2);
+}
+
+void MainWindow::slotTableSelected()
+{
+ QTW *table = _ui->wid_table;
+ NCFile entry = _vfs->fileGet(table->currentRow());
+
+ if (entry.name().count("/"))
+ _ui->act_file_conv_win->setEnabled(true);
+ else
+ _ui->act_file_conv_win->setEnabled(false);
+
+ if (entry.name().count("\\"))
+ _ui->act_file_conv_lin->setEnabled(true);
+ else
+ _ui->act_file_conv_lin->setEnabled(false);
+
+ setMode(Mode::Selected);
+}
+
+void MainWindow::slotTableChange(qint32 row)
+{
+ QTW *table = _ui->wid_table;
+ NCFile entry = _vfs->fileGet(row);
+
+ entry.setName(table->item(row, 5)->text());
+ entry.setNameLength(entry.name().size() + 1);
+ entry.setHSize(entry.headerSize() + entry.nameLength());
+
+ _vfs->fileReplace(entry, row);
+ slotStatusUpdate();
+}
+
+void MainWindow::slotTableStatus(quint32 from_row, quint32 to_row, ColType cols)
+{
+ QTW *table = _ui->wid_table;
+ QTWI *it0 = 0;
+ QTWI *it1 = 0;
+ QTWI *it2 = 0;
+ QTWI *it3 = 0;
+ QTWI *it4 = 0;
+ QTWI *it5 = 0;
+ QTWI *it6 = 0;
+
+ // if that happens, something is very very odd
+ if (to_row != _vfs->count())
+ qDebug() << "it happend! oh my god, it happend!!";
+
+ // if these do not fit, we have a full refresh and have to build every single
+ // table item
+ if (to_row != static_cast<quint32>(table->rowCount()))
+ {
+ table->setRowCount(to_row);
+ for (quint32 row = 0; row < to_row; ++row)
+ {
+ NCFile entry = _vfs->fileGet(row);
+
+ it0 = new QTWI(QString::number(entry.hSize()));
+ it1 = new QTWI(QString::number(entry.position()));
+ it2 = new QTWI(QString::number(entry.cSize()));
+ it3 = new QTWI(QString::number(entry.oSize()));
+ it4 = new QTWI(QString::number(entry.nameLength()));
+ it5 = new QTWI(entry.name());
+ it6 = new QTWI(QString(QCH::hash(entry.cData(), QCH::Sha1).toHex().toUpper()));
+
+ it0->setBackground(Grey);
+ it0->setFlags(it0->flags() ^ Qt::ItemIsEditable);
+ it0->setTextAlignment(Qt::AlignRight);
+
+ it1->setBackground(Grey);
+ it1->setFlags(it1->flags() ^ Qt::ItemIsEditable);
+ it1->setTextAlignment(Qt::AlignRight);
+
+ it2->setBackground(Grey);
+ it2->setFlags(it2->flags() ^ Qt::ItemIsEditable);
+ it2->setTextAlignment(Qt::AlignRight);
+
+ it3->setBackground(Grey);
+ it3->setFlags(it3->flags() ^ Qt::ItemIsEditable);
+ it3->setTextAlignment(Qt::AlignRight);
+
+ it4->setBackground(Grey);
+ it4->setFlags(it4->flags() ^ Qt::ItemIsEditable);
+ it4->setTextAlignment(Qt::AlignRight);
+
+ it5->setBackground(Green);
+ it5->setTextAlignment(Qt::AlignLeft);
+
+ it6->setBackground(Grey);
+ it6->setFlags(it6->flags() ^ Qt::ItemIsEditable);
+ it6->setTextAlignment(Qt::AlignLeft);
+
+ switch (cols)
+ {
+ case ColType::HSize:
+ it0->setBackground(Red);
+ break;
+
+ case ColType::Position:
+ it1->setBackground(Red);
+ break;
+
+ case ColType::CSize:
+ it2->setBackground(Red);
+ break;
+
+ case ColType::OSize:
+ it3->setBackground(Red);
+ break;
+
+ case ColType::NameLength:
+ it4->setBackground(Red);
+ break;
+
+ case ColType::Name:
+ it5->setBackground(Red);
+ break;
+
+ case ColType::CData:
+ case ColType::OData:
+ break;
+
+ case ColType::All:
+ it0->setBackground(Red);
+ it1->setBackground(Red);
+ it2->setBackground(Red);
+ it3->setBackground(Red);
+ it4->setBackground(Red);
+ it5->setBackground(Red);
+ it6->setBackground(Red);
+ break;
+
+ case ColType::None:
+ default:
+ it0->setBackground(Grey);
+ it1->setBackground(Grey);
+ it2->setBackground(Grey);
+ it3->setBackground(Grey);
+ it4->setBackground(Grey);
+ it5->setBackground(Green);
+ it6->setBackground(Grey);
+ }
+
+ disconnect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+
+ table->setItem(row, 0, it0);
+ table->setItem(row, 1, it1);
+ table->setItem(row, 2, it2);
+ table->setItem(row, 3, it3);
+ table->setItem(row, 4, it4);
+ table->setItem(row, 5, it5);
+ table->setItem(row, 6, it6);
+
+ connect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+ }
+ }
+ else
+ {
+ disconnect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+
+ for (quint32 row = 0; row < to_row; ++row)
+ {
+ NCFile entry = _vfs->fileGet(row);
+
+ table->item(row, 1)->setText(QString::number(entry.position()));
+ }
+
+ for (quint32 row = from_row; row < to_row; ++row)
+ {
+ switch (cols)
+ {
+ case ColType::HSize:
+ table->item(row, 0)->setBackground(Red);
+ break;
+
+ case ColType::Position:
+ table->item(row, 1)->setBackground(Red);
+ break;
+
+ case ColType::CSize:
+ table->item(row, 2)->setBackground(Red);
+ break;
+
+ case ColType::OSize:
+ table->item(row, 3)->setBackground(Red);
+ break;
+
+ case ColType::NameLength:
+ table->item(row, 4)->setBackground(Red);
+ break;
+
+ case ColType::Name:
+ table->item(row, 5)->setBackground(Red);
+ break;
+
+ case ColType::CData:
+ case ColType::OData:
+ break;
+
+ case ColType::All:
+ table->item(row, 0)->setBackground(Red);
+ table->item(row, 1)->setBackground(Red);
+ table->item(row, 2)->setBackground(Red);
+ table->item(row, 3)->setBackground(Red);
+ table->item(row, 4)->setBackground(Red);
+ table->item(row, 5)->setBackground(Red);
+ table->item(row, 6)->setBackground(Red);
+ break;
+
+ case ColType::None:
+ default:
+ table->item(row, 0)->setBackground(Grey);
+ table->item(row, 1)->setBackground(Grey);
+ table->item(row, 2)->setBackground(Grey);
+ table->item(row, 3)->setBackground(Grey);
+ table->item(row, 4)->setBackground(Grey);
+ table->item(row, 5)->setBackground(Green);
+ table->item(row, 6)->setBackground(Grey);
+ }
+ }
+
+ connect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+ }
+
+ table->resizeColumnsToContents();
+}
+
+void MainWindow::slotTableAdd(NCFile& entry, quint32 row)
+{
+ QTW *table = _ui->wid_table;
+ QTWI *it0 = new QTWI(QString::number(entry.hSize()));
+ QTWI *it1 = new QTWI(QString::number(entry.position()));
+ QTWI *it2 = new QTWI(QString::number(entry.cSize()));
+ QTWI *it3 = new QTWI(QString::number(entry.oSize()));
+ QTWI *it4 = new QTWI(QString::number(entry.nameLength()));
+ QTWI *it5 = new QTWI(entry.name());
+ QTWI *it6 = new QTWI(QString(QCH::hash(entry.cData(), QCH::Sha1).toHex().toUpper()));
+
+ it0->setBackground(Red);
+ it0->setFlags(it0->flags() ^ Qt::ItemIsEditable);
+ it0->setTextAlignment(Qt::AlignRight);
+
+ it1->setBackground(Red);
+ it1->setFlags(it1->flags() ^ Qt::ItemIsEditable);
+ it1->setTextAlignment(Qt::AlignRight);
+
+ it2->setBackground(Red);
+ it2->setFlags(it2->flags() ^ Qt::ItemIsEditable);
+ it2->setTextAlignment(Qt::AlignRight);
+
+ it3->setBackground(Red);
+ it3->setFlags(it3->flags() ^ Qt::ItemIsEditable);
+ it3->setTextAlignment(Qt::AlignRight);
+
+ it4->setBackground(Red);
+ it4->setFlags(it4->flags() ^ Qt::ItemIsEditable);
+ it4->setTextAlignment(Qt::AlignRight);
+
+ it5->setBackground(Red);
+ it5->setTextAlignment(Qt::AlignLeft);
+
+ it6->setBackground(Red);
+ it6->setFlags(it6->flags() ^ Qt::ItemIsEditable);
+ it6->setTextAlignment(Qt::AlignLeft);
+
+ disconnect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+
+ table->insertRow(row);
+ table->setItem(row, 0, it0);
+ table->setItem(row, 1, it1);
+ table->setItem(row, 2, it2);
+ table->setItem(row, 3, it3);
+ table->setItem(row, 4, it4);
+ table->setItem(row, 5, it5);
+ table->setItem(row, 6, it6);
+
+ connect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+}
+
+void MainWindow::slotTableReplace(NCFile& entry, quint32 row)
+{
+ QTW *table = _ui->wid_table;
+
+ disconnect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+
+ table->item(row, 0)->setText(QString::number(entry.hSize()));
+ table->item(row, 0)->setBackground(Red);
+
+ table->item(row, 1)->setText(QString::number(entry.position()));
+ table->item(row, 1)->setBackground(Red);
+
+ table->item(row, 2)->setText(QString::number(entry.cSize()));
+ table->item(row, 2)->setBackground(Red);
+
+ table->item(row, 3)->setText(QString::number(entry.oSize()));
+ table->item(row, 3)->setBackground(Red);
+
+ table->item(row, 4)->setText(QString::number(entry.nameLength()));
+ table->item(row, 4)->setBackground(Red);
+
+ table->item(row, 5)->setText(entry.name());
+ table->item(row, 5)->setBackground(Red);
+
+ table->item(row, 6)->setText(QString(QCH::hash(entry.cData(), QCH::Sha1).toHex().toUpper()));
+ table->item(row, 6)->setBackground(Red);
+
+ connect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+}
+
+void MainWindow::slotTableRemove(quint32 row)
+{
+ _ui->wid_table->removeRow(row);
+}
+
+// --- protected methods ---
+
+void MainWindow::changeEvent(QEvent *event)
+{
+ if (event->type() == QEvent::LanguageChange)
+ _ui->retranslateUi(this);
+ else
+ QMainWindow::changeEvent(event);
+}
+
+void MainWindow::setLanguage(const Language::Type lang)
+{
+ QTranslator *translator = new QTranslator(this);
+
+ if (translator)
+ {
+ switch (lang)
+ {
+ case Language::French:
+ translator->load(":/Language/French");
+ break;
+ case Language::German:
+ translator->load(":/Language/German");
+ break;
+ case Language::English:
+ default:
+ translator->load(":/Language/English");
+ }
+
+ if (!translator->isEmpty())
+ {
+ qApp->removeTranslator(_translator);
+ delete _translator;
+ _translator = translator;
+ qApp->installTranslator(_translator);
+
+ _ui->act_lang_english->setEnabled(true);
+ _ui->act_lang_french->setEnabled(true);
+ _ui->act_lang_german->setEnabled(true);
+
+ switch (lang)
+ {
+ case Language::French:
+ _ui->act_lang_french->setEnabled(false);
+ break;
+ case Language::German:
+ _ui->act_lang_german->setEnabled(false);
+ break;
+ case Language::English:
+ default:
+ _ui->act_lang_english->setEnabled(false);
+ }
+ }
+ else
+ delete translator;
+ }
+}
+
+void MainWindow::setMode(const Mode::Type mode)
+{
+ switch (mode)
+ {
+ case Mode::Fresh:
+ _filename = "";
+ _ui->act_app_open->setEnabled(true);
+ _ui->act_app_save->setEnabled(false);
+ _ui->act_app_saveas->setEnabled(false);
+ _ui->act_file_replace->setEnabled(false);
+ _ui->act_file_remove->setEnabled(false);
+ _ui->act_file_save_plain->setEnabled(false);
+ _ui->act_file_save_pak->setEnabled(false);
+ _ui->act_file_save_zlib->setEnabled(false);
+ _ui->act_file_conv_win->setEnabled(false);
+ _ui->act_file_conv_lin->setEnabled(false);
+ break;
+ case Mode::Edited:
+ _ui->act_app_open->setEnabled(false);
+ _ui->act_app_save->setEnabled(true);
+ _ui->act_app_saveas->setEnabled(true);
+ _ui->act_file_replace->setEnabled(false);
+ _ui->act_file_remove->setEnabled(false);
+ _ui->act_file_save_plain->setEnabled(false);
+ _ui->act_file_save_pak->setEnabled(false);
+ _ui->act_file_save_zlib->setEnabled(false);
+ break;
+ case Mode::Selected:
+ _ui->act_app_open->setEnabled(false);
+ _ui->act_app_save->setEnabled(true);
+ _ui->act_app_saveas->setEnabled(true);
+ _ui->act_file_replace->setEnabled(true);
+ _ui->act_file_remove->setEnabled(true);
+ _ui->act_file_save_plain->setEnabled(true);
+ _ui->act_file_save_pak->setEnabled(true);
+ _ui->act_file_save_zlib->setEnabled(true);
+ break;
+ }
+}
+
+void MainWindow::setupActions()
+{
+ QTW *table = _ui->wid_table;
+ QAction *ctx_sep1 = new QAction(this);
+ QAction *ctx_sep2 = new QAction(this);
+ QAction *ctx_sep3 = new QAction(this);
+
+ // all the nice connections we need for the GUI
+ connect(_ui->act_app_new, SIGNAL(triggered()),
+ this, SLOT(slotAppNew()));
+ connect(_ui->act_app_open, SIGNAL(triggered()),
+ this, SLOT(slotAppOpen()));
+ connect(_ui->act_app_save, SIGNAL(triggered()),
+ this, SLOT(slotAppSave()));
+ connect(_ui->act_app_saveas, SIGNAL(triggered()),
+ this, SLOT(slotAppSaveAs()));
+ connect(_ui->act_app_quit, SIGNAL(triggered()),
+ this, SLOT(slotAppQuit()));
+
+ connect(_ui->act_file_add, SIGNAL(triggered()),
+ this, SLOT(slotFileAdd()));
+ connect(_ui->act_file_replace, SIGNAL(triggered()),
+ this, SLOT(slotFileReplace()));
+ connect(_ui->act_file_remove, SIGNAL(triggered()),
+ this, SLOT(slotFileRemove()));
+ connect(_ui->act_file_save_plain, SIGNAL(triggered()),
+ this, SLOT(slotFileSavePlain()));
+ connect(_ui->act_file_save_pak, SIGNAL(triggered()),
+ this, SLOT(slotFileSavePAK()));
+ connect(_ui->act_file_save_zlib, SIGNAL(triggered()),
+ this, SLOT(slotFileSaveZLIB()));
+ connect(_ui->act_file_conv_win, SIGNAL(triggered()),
+ this, SLOT(slotFileConvWin()));
+ connect(_ui->act_file_conv_lin, SIGNAL(triggered()),
+ this, SLOT(slotFileConvLin()));
+
+ connect(_ui->act_lang_english, SIGNAL(triggered()),
+ this, SLOT(slotLangEnglish()));
+ connect(_ui->act_lang_french, SIGNAL(triggered()),
+ this, SLOT(slotLangFrench()));
+ connect(_ui->act_lang_german, SIGNAL(triggered()),
+ this, SLOT(slotLangGerman()));
+
+ connect(_ui->act_style_default, SIGNAL(triggered()),
+ this, SLOT(slotStyleDefault()));
+ connect(_ui->act_style_fusion, SIGNAL(triggered()),
+ this, SLOT(slotStyleFusion()));
+ connect(_ui->act_style_windows, SIGNAL(triggered()),
+ this, SLOT(slotStyleWindows()));
+ connect(_ui->act_style_gtk, SIGNAL(triggered()),
+ this, SLOT(slotStyleGTK()));
+
+ connect(_ui->act_about_app, SIGNAL(triggered()),
+ this, SLOT(slotAboutApp()));
+ connect(_ui->act_about_qt, SIGNAL(triggered()),
+ this, SLOT(slotAboutQt()));
+
+ // table update connections
+ connect(table, SIGNAL(cellPressed(qint32, qint32)),
+ this, SLOT(slotTableSelected()));
+ connect(table, SIGNAL(cellChanged(qint32, qint32)),
+ this, SLOT(slotTableChange(qint32)));
+
+ connect(_vfs, SIGNAL(sigFileStatus(quint32, quint32, ColType)),
+ this, SLOT(slotTableStatus(quint32, quint32, ColType)));
+ connect(_vfs, SIGNAL(sigFileAdd(NCFile&, quint32)),
+ this, SLOT(slotTableAdd(NCFile&, quint32)));
+ connect(_vfs, SIGNAL(sigFileReplace(NCFile&, quint32)),
+ this, SLOT(slotTableReplace(NCFile&, quint32)));
+ connect(_vfs, SIGNAL(sigFileRemove(quint32)),
+ this, SLOT(slotTableRemove(quint32)));
+
+ // context menus for the QTableWidget
+ ctx_sep1->setSeparator(true);
+ ctx_sep2->setSeparator(true);
+ ctx_sep3->setSeparator(true);
+
+ table->addAction(_ui->act_file_add);
+ table->addAction(ctx_sep1);
+ table->addAction(_ui->act_file_replace);
+ table->addAction(_ui->act_file_remove);
+ table->addAction(ctx_sep2);
+ table->addAction(_ui->act_file_save_plain);
+ table->addAction(_ui->act_file_save_pak);
+ table->addAction(_ui->act_file_save_zlib);
+ table->addAction(ctx_sep3);
+ table->addAction(_ui->act_file_conv_win);
+ table->addAction(_ui->act_file_conv_lin);
+}
--- /dev/null
+#pragma once
+
+#include <QMainWindow>
+#include "common/NCTypes.hxx"
+
+namespace Ui
+{
+ class MainWindow;
+}
+class QSettings;
+class QTranslator;
+class NCFile;
+class NCFilesystem;
+
+namespace Language
+{
+ enum Type : quint8 {
+ English,
+ French,
+ German
+ };
+}
+
+namespace Mode
+{
+ enum Type : quint8 {
+ Fresh,
+ Edited,
+ Selected
+ };
+}
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ // internal typedefs
+ using ColType = NC::FileData::Type;
+
+ // constructors and deconstructors
+ explicit MainWindow(QWidget *parent = 0);
+ virtual ~MainWindow();
+
+public slots:
+ // public slots
+ void slotAppNew();
+ void slotAppOpen();
+ void slotAppSave();
+ void slotAppSaveAs();
+ void slotAppQuit();
+
+ void slotFileAdd();
+ void slotFileReplace();
+ void slotFileRemove();
+ void slotFileSavePlain();
+ void slotFileSavePAK();
+ void slotFileSaveZLIB();
+ void slotFileConvWin();
+ void slotFileConvLin();
+
+ void slotLangEnglish();
+ void slotLangFrench();
+ void slotLangGerman();
+
+ void slotStyleDefault();
+ void slotStyleFusion();
+ void slotStyleWindows();
+ void slotStyleGTK();
+
+ void slotAboutApp();
+ void slotAboutQt();
+
+ void slotStatusUpdate();
+
+ void slotTableSelected();
+ void slotTableChange(qint32 row);
+ void slotTableStatus(quint32 from_row, quint32 to_row, ColType cols);
+ void slotTableAdd(NCFile& entry, quint32 row);
+ void slotTableReplace(NCFile& entry, quint32 row);
+ void slotTableRemove(quint32 row);
+
+protected:
+ // protected stuff
+ virtual void changeEvent(QEvent *event);
+ void setLanguage(const Language::Type lang = Language::English);
+ void setMode(const Mode::Type mode = Mode::Fresh);
+ void setupActions();
+
+private:
+ Ui::MainWindow *_ui;
+ QTranslator *_translator;
+ QSettings *_settings;
+ NCFilesystem *_vfs;
+ QVector<QPair<qint32, qint32>> _marks;
+ QString _filename;
+};
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>FRM-MAINWINDOW</string>
+ </property>
+ <property name="locale">
+ <locale language="English" country="UnitedStates"/>
+ </property>
+ <widget class="QWidget" name="wid_center">
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QTableWidget" name="wid_table">
+ <property name="contextMenuPolicy">
+ <enum>Qt::ActionsContextMenu</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="mm_app">
+ <property name="title">
+ <string>MM-APP</string>
+ </property>
+ <addaction name="act_app_new"/>
+ <addaction name="separator"/>
+ <addaction name="act_app_open"/>
+ <addaction name="act_app_save"/>
+ <addaction name="act_app_saveas"/>
+ <addaction name="separator"/>
+ <addaction name="act_app_quit"/>
+ </widget>
+ <widget class="QMenu" name="mm_about">
+ <property name="title">
+ <string>MM-ABOUT</string>
+ </property>
+ <addaction name="act_about_app"/>
+ <addaction name="act_about_qt"/>
+ </widget>
+ <widget class="QMenu" name="mm_conf">
+ <property name="title">
+ <string>MM-CONF</string>
+ </property>
+ <widget class="QMenu" name="sm_lang">
+ <property name="title">
+ <string>SM-LANG</string>
+ </property>
+ <addaction name="act_lang_english"/>
+ <addaction name="act_lang_french"/>
+ <addaction name="act_lang_german"/>
+ </widget>
+ <widget class="QMenu" name="sm_style">
+ <property name="title">
+ <string>SM-STYLE</string>
+ </property>
+ <addaction name="act_style_default"/>
+ <addaction name="separator"/>
+ <addaction name="act_style_fusion"/>
+ <addaction name="act_style_windows"/>
+ <addaction name="act_style_gtk"/>
+ </widget>
+ <addaction name="sm_lang"/>
+ <addaction name="sm_style"/>
+ </widget>
+ <widget class="QMenu" name="mm_file">
+ <property name="title">
+ <string>MM-FILE</string>
+ </property>
+ <addaction name="act_file_add"/>
+ <addaction name="separator"/>
+ <addaction name="act_file_replace"/>
+ <addaction name="act_file_remove"/>
+ <addaction name="separator"/>
+ <addaction name="act_file_save_plain"/>
+ <addaction name="act_file_save_pak"/>
+ <addaction name="act_file_save_zlib"/>
+ <addaction name="separator"/>
+ <addaction name="act_file_conv_win"/>
+ <addaction name="act_file_conv_lin"/>
+ </widget>
+ <addaction name="mm_app"/>
+ <addaction name="mm_file"/>
+ <addaction name="mm_conf"/>
+ <addaction name="mm_about"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <action name="act_app_quit">
+ <property name="text">
+ <string>ME-APP-QUIT</string>
+ </property>
+ </action>
+ <action name="act_app_new">
+ <property name="text">
+ <string>ME-APP-NEW</string>
+ </property>
+ </action>
+ <action name="act_app_open">
+ <property name="text">
+ <string>ME-APP-OPEN</string>
+ </property>
+ </action>
+ <action name="act_app_save">
+ <property name="text">
+ <string>ME-APP-SAVE</string>
+ </property>
+ </action>
+ <action name="act_app_saveas">
+ <property name="text">
+ <string>ME-APP-SAVEAS</string>
+ </property>
+ </action>
+ <action name="act_about_app">
+ <property name="text">
+ <string>ME-ABOUT-APP</string>
+ </property>
+ </action>
+ <action name="act_about_qt">
+ <property name="text">
+ <string>ME-ABOUT-QT</string>
+ </property>
+ </action>
+ <action name="act_lang_english">
+ <property name="text">
+ <string>ME-LANG-ENGLISH</string>
+ </property>
+ </action>
+ <action name="act_lang_french">
+ <property name="text">
+ <string>ME-LANG-FRENCH</string>
+ </property>
+ </action>
+ <action name="act_lang_german">
+ <property name="text">
+ <string>ME-LANG-GERMAN</string>
+ </property>
+ </action>
+ <action name="act_style_default">
+ <property name="text">
+ <string>ME-STYLE-DEFAULT</string>
+ </property>
+ </action>
+ <action name="act_style_windows">
+ <property name="text">
+ <string>ME-STYLE-WINDOWS</string>
+ </property>
+ </action>
+ <action name="act_style_gtk">
+ <property name="text">
+ <string>ME-STYLE-GTK</string>
+ </property>
+ </action>
+ <action name="act_style_fusion">
+ <property name="text">
+ <string>ME-STYLE-FUSION</string>
+ </property>
+ </action>
+ <action name="act_file_add">
+ <property name="text">
+ <string>ME-FILE-ADD</string>
+ </property>
+ </action>
+ <action name="act_file_replace">
+ <property name="text">
+ <string>ME-FILE-REPLACE</string>
+ </property>
+ </action>
+ <action name="act_file_remove">
+ <property name="text">
+ <string>ME-FILE-REMOVE</string>
+ </property>
+ </action>
+ <action name="act_file_save_plain">
+ <property name="text">
+ <string>ME-FILE-SAVE-PLAIN</string>
+ </property>
+ </action>
+ <action name="act_file_save_pak">
+ <property name="text">
+ <string>ME-FILE-SAVE-PAK</string>
+ </property>
+ </action>
+ <action name="act_file_save_zlib">
+ <property name="text">
+ <string>ME-FILE-SAVE-ZLIB</string>
+ </property>
+ </action>
+ <action name="act_file_conv_win">
+ <property name="text">
+ <string>ME-FILE-CONV-WIN</string>
+ </property>
+ </action>
+ <action name="act_file_conv_lin">
+ <property name="text">
+ <string>ME-FILE-CONV-LIN</string>
+ </property>
+ </action>
+ </widget>
+ <resources>
+ <include location="Resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
--- /dev/null
+<RCC>
+ <qresource prefix="Language">
+ <file alias="English">i18n_english.qm</file>
+ <file alias="French">i18n_french.qm</file>
+ <file alias="German">i18n_german.qm</file>
+ </qresource>
+</RCC>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="en_US">
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="MainWindow.ui" line="14"/>
+ <location filename="MainWindow.cxx" line="221"/>
+ <source>FRM-MAINWINDOW</source>
+ <translation>QTinNS Editor</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="56"/>
+ <source>MM-APP</source>
+ <translation>Filesystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="68"/>
+ <source>MM-ABOUT</source>
+ <translation>About</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="75"/>
+ <source>MM-CONF</source>
+ <translation>Configuration</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="79"/>
+ <source>SM-LANG</source>
+ <translation>Language</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="87"/>
+ <source>SM-STYLE</source>
+ <translation>GUI Style</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="100"/>
+ <source>MM-FILE</source>
+ <translation>File</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="122"/>
+ <source>ME-APP-QUIT</source>
+ <translation>Quit</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="127"/>
+ <source>ME-APP-NEW</source>
+ <translation>New virtual filesystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="132"/>
+ <source>ME-APP-OPEN</source>
+ <translation>Open virtual filesystem ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="137"/>
+ <source>ME-APP-SAVE</source>
+ <translation>Save virtual filesystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="142"/>
+ <source>ME-APP-SAVEAS</source>
+ <translation>Save virtual filesystem as ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="147"/>
+ <source>ME-ABOUT-APP</source>
+ <translation>About QTinNS Editor ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="152"/>
+ <source>ME-ABOUT-QT</source>
+ <translation>About Qt framework ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="157"/>
+ <source>ME-LANG-ENGLISH</source>
+ <translation>English</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="162"/>
+ <source>ME-LANG-FRENCH</source>
+ <translation>French</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="167"/>
+ <source>ME-LANG-GERMAN</source>
+ <translation>German</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="172"/>
+ <source>ME-STYLE-DEFAULT</source>
+ <translation>System Default</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="177"/>
+ <source>ME-STYLE-WINDOWS</source>
+ <oldsource>ME-STYLE-CDE</oldsource>
+ <translation>Windows</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="182"/>
+ <source>ME-STYLE-GTK</source>
+ <oldsource>ME-STYLE-CLEANLOOKS</oldsource>
+ <translation>GTK+</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="187"/>
+ <source>ME-STYLE-FUSION</source>
+ <oldsource>ME-STYLE-PLASTIQUE</oldsource>
+ <translation>Fusion</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="192"/>
+ <source>ME-FILE-ADD</source>
+ <translation>Add file(s) ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="197"/>
+ <source>ME-FILE-REPLACE</source>
+ <translation>Replace file ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="202"/>
+ <source>ME-FILE-REMOVE</source>
+ <translation>Remove file ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="207"/>
+ <source>ME-FILE-SAVE-PLAIN</source>
+ <translation>Save plain file as ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="212"/>
+ <source>ME-FILE-SAVE-PAK</source>
+ <translation>Save PAK file as ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="217"/>
+ <source>ME-FILE-SAVE-ZLIB</source>
+ <translation>Save ZLIB file as ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="222"/>
+ <source>ME-FILE-CONV-WIN</source>
+ <translation>Convert UNIX path to Windows path</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="227"/>
+ <source>ME-FILE-CONV-LIN</source>
+ <translation>Convert Windows path to UNIX path</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>DIA-OPEN-FILE</source>
+ <translation>Open files ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>FLT-FILE-VFS</source>
+ <oldsource>DIA-SAVE-FILE</oldsource>
+ <translation>Neocron VFS file (*.vfs *.pak)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <source>DIA-OPEN-VFS</source>
+ <translation>Open virtual filesystem ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>DIA-SAVE-VFS</source>
+ <translation>Save virtual filesystem ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>FLT-FILE-ANY</source>
+ <translation>File (*.*)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>DIA-SAVE-PLAIN</source>
+ <translation>Save file ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>FLT-FILE-PLAIN</source>
+ <translation>File (*.*)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>DIA-SAVE-PAK</source>
+ <translation>Save PAK file ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>FLT-FILE-PAK</source>
+ <translation>Neocron PAK file (*.pak)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>DIA-SAVE-ZLIB</source>
+ <translation>Save ZLIB file ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>FLT-FILE-ZLIB</source>
+ <translation>ZLIB file (*.z)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-FILE</source>
+ <translation>Virtual filesystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-WITH</source>
+ <translation>with</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="220"/>
+ <source>MSG-UPD-ENTRIES</source>
+ <translation>entries</translation>
+ </message>
+</context>
+</TS>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="MainWindow.ui" line="14"/>
+ <location filename="MainWindow.cxx" line="221"/>
+ <source>FRM-MAINWINDOW</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="56"/>
+ <source>MM-APP</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="68"/>
+ <source>MM-ABOUT</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="75"/>
+ <source>MM-CONF</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="79"/>
+ <source>SM-LANG</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="87"/>
+ <source>SM-STYLE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="100"/>
+ <source>MM-FILE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="122"/>
+ <source>ME-APP-QUIT</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="127"/>
+ <source>ME-APP-NEW</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="132"/>
+ <source>ME-APP-OPEN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="137"/>
+ <source>ME-APP-SAVE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="142"/>
+ <source>ME-APP-SAVEAS</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="147"/>
+ <source>ME-ABOUT-APP</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="152"/>
+ <source>ME-ABOUT-QT</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="157"/>
+ <source>ME-LANG-ENGLISH</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="162"/>
+ <source>ME-LANG-FRENCH</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="167"/>
+ <source>ME-LANG-GERMAN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="172"/>
+ <source>ME-STYLE-DEFAULT</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="177"/>
+ <source>ME-STYLE-WINDOWS</source>
+ <oldsource>ME-STYLE-CDE</oldsource>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="182"/>
+ <source>ME-STYLE-GTK</source>
+ <oldsource>ME-STYLE-CLEANLOOKS</oldsource>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="187"/>
+ <source>ME-STYLE-FUSION</source>
+ <oldsource>ME-STYLE-PLASTIQUE</oldsource>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="192"/>
+ <source>ME-FILE-ADD</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="197"/>
+ <source>ME-FILE-REPLACE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="202"/>
+ <source>ME-FILE-REMOVE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="207"/>
+ <source>ME-FILE-SAVE-PLAIN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="212"/>
+ <source>ME-FILE-SAVE-PAK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="217"/>
+ <source>ME-FILE-SAVE-ZLIB</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="222"/>
+ <source>ME-FILE-CONV-WIN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="227"/>
+ <source>ME-FILE-CONV-LIN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>DIA-OPEN-FILE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>FLT-FILE-VFS</source>
+ <oldsource>DIA-SAVE-FILE</oldsource>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <source>DIA-OPEN-VFS</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>DIA-SAVE-VFS</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>FLT-FILE-ANY</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>DIA-SAVE-PLAIN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>FLT-FILE-PLAIN</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>DIA-SAVE-PAK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>FLT-FILE-PAK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>DIA-SAVE-ZLIB</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>FLT-FILE-ZLIB</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-FILE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-WITH</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="220"/>
+ <source>MSG-UPD-ENTRIES</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE">
+<context>
+ <name>MainWindow</name>
+ <message>
+ <location filename="MainWindow.ui" line="14"/>
+ <location filename="MainWindow.cxx" line="221"/>
+ <source>FRM-MAINWINDOW</source>
+ <translation>QTinNS Editor</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="56"/>
+ <source>MM-APP</source>
+ <translation>Dateisystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="68"/>
+ <source>MM-ABOUT</source>
+ <translation>Über</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="75"/>
+ <source>MM-CONF</source>
+ <translation>Konfiguration</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="79"/>
+ <source>SM-LANG</source>
+ <translation>Sprache</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="87"/>
+ <source>SM-STYLE</source>
+ <translation>GUI Stil</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="100"/>
+ <source>MM-FILE</source>
+ <translation>Datei</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="122"/>
+ <source>ME-APP-QUIT</source>
+ <translation>Beenden</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="127"/>
+ <source>ME-APP-NEW</source>
+ <translation>Neues virtuelles Dateisystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="132"/>
+ <source>ME-APP-OPEN</source>
+ <translation>Virtuelles Dateisystem öffnen ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="137"/>
+ <source>ME-APP-SAVE</source>
+ <translation>Virtuelles Dateisystem speichern</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="142"/>
+ <source>ME-APP-SAVEAS</source>
+ <translation>Virtuelles Dateisystem speichern als ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="147"/>
+ <source>ME-ABOUT-APP</source>
+ <translation>Über QTinNS Editor ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="152"/>
+ <source>ME-ABOUT-QT</source>
+ <translation>Über Qt Framework ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="157"/>
+ <source>ME-LANG-ENGLISH</source>
+ <translation>Englisch</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="162"/>
+ <source>ME-LANG-FRENCH</source>
+ <translation>Französisch</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="167"/>
+ <source>ME-LANG-GERMAN</source>
+ <translation>Deutsch</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="172"/>
+ <source>ME-STYLE-DEFAULT</source>
+ <translation>System Standard</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="177"/>
+ <source>ME-STYLE-WINDOWS</source>
+ <oldsource>ME-STYLE-CDE</oldsource>
+ <translation>Windows</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="182"/>
+ <source>ME-STYLE-GTK</source>
+ <oldsource>ME-STYLE-CLEANLOOKS</oldsource>
+ <translation>GTK+</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="187"/>
+ <source>ME-STYLE-FUSION</source>
+ <oldsource>ME-STYLE-PLASTIQUE</oldsource>
+ <translation>Fusion</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="192"/>
+ <source>ME-FILE-ADD</source>
+ <translation>Füge Datei(en) hinzu ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="197"/>
+ <source>ME-FILE-REPLACE</source>
+ <translation>Ersetze Datei ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="202"/>
+ <source>ME-FILE-REMOVE</source>
+ <translation>Entferne Datei ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="207"/>
+ <source>ME-FILE-SAVE-PLAIN</source>
+ <translation>Speichere normale Datei als ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="212"/>
+ <source>ME-FILE-SAVE-PAK</source>
+ <translation>Speichere PAK Datei als ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="217"/>
+ <source>ME-FILE-SAVE-ZLIB</source>
+ <translation>Speichere ZLIB Datei als ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="222"/>
+ <source>ME-FILE-CONV-WIN</source>
+ <translation>Konvertiere UNIX Pfad nach Windows</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.ui" line="227"/>
+ <source>ME-FILE-CONV-LIN</source>
+ <translation>Konvertiere Windows Pfad nach UNIX</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>DIA-OPEN-FILE</source>
+ <translation>Datei öffnen ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>FLT-FILE-VFS</source>
+ <oldsource>DIA-SAVE-FILE</oldsource>
+ <translation>Neocron VFS Datei (*.vfs *.pak)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="86"/>
+ <source>DIA-OPEN-VFS</source>
+ <translation>Virtuelles Dateisystem öffnen ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="106"/>
+ <source>DIA-SAVE-VFS</source>
+ <translation>Virtuelles Dateisystem speichern ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="122"/>
+ <location filename="MainWindow.cxx" line="133"/>
+ <source>FLT-FILE-ANY</source>
+ <translation>Datei (*.*)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>DIA-SAVE-PLAIN</source>
+ <translation>Datei speichern ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="151"/>
+ <source>FLT-FILE-PLAIN</source>
+ <translation>Datei (*.*)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>DIA-SAVE-PAK</source>
+ <translation>PAK Datei speichern ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="159"/>
+ <source>FLT-FILE-PAK</source>
+ <translation>Neocron PAK Datei (*.pak)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>DIA-SAVE-ZLIB</source>
+ <translation>ZLIB Datei speichern ...</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="167"/>
+ <source>FLT-FILE-ZLIB</source>
+ <translation>ZLIB Datei (*.z)</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-FILE</source>
+ <translation>Virtuelles Dateisystem</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="219"/>
+ <source>MSG-UPD-WITH</source>
+ <translation>mit</translation>
+ </message>
+ <message>
+ <location filename="MainWindow.cxx" line="220"/>
+ <source>MSG-UPD-ENTRIES</source>
+ <translation>Einträgen</translation>
+ </message>
+</context>
+</TS>
--- /dev/null
+# Qt sources
+set (NCF_SOURCES FileIdentifier.cxx NCFile.cxx NCFilesystem.cxx)
+set (NCF_HEADERS FileIdentifier.hxx NCFile.hxx NCFilesystem.hxx)
+set (NCF_UI_FILES )
+set (NCF_RES_FILES )
+set (E_TS_FILES )
+
+# wrappers
+QT5_ADD_TRANSLATION (NCF_TS_SOURCES ${NCF_TS_FILES})
+QT5_WRAP_CPP (NCF_MOC_SOURCES ${NCF_HEADERS})
+QT5_WRAP_UI (NCF_UI_SOURCES ${NCF_UI_FILES})
+QT5_ADD_RESOURCES (NCF_RES_SOURCES ${NCF_RES_FILES})
+
+# libs
+add_library (Filesystem ${NCF_SOURCES} ${NCF_MOC_SOURCES} ${NCF_UI_SOURCES} ${NCF_RES_SOURCES}
+ ${NCF_TS_SOURCES})
+qt5_use_modules (Filesystem Core)
--- /dev/null
+#include <QFile>
+#include "filesystem/FileIdentifier.hxx"
+
+// --- internal typedefs ---
+
+using IdentifyType = NC::Identify::Type;
+
+// --- constructors and deconstructors ---
+
+FileIdentifier::FileIdentifier(QObject *parent)
+: QObject(parent)
+{
+}
+
+FileIdentifier::~FileIdentifier()
+{
+}
+
+// --- public methodes ---
+
+IdentifyType FileIdentifier::identify(const QString& filename) const
+{
+ QFile ifile(filename);
+ quint32 data = 0;
+
+ if (!ifile.exists())
+ return IdentifyType::Error;
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ ifile.close();
+ }
+ else
+ return IdentifyType::Error;
+
+ return identifyData(data);
+}
+
+IdentifyType FileIdentifier::identify(const QByteArray& stream) const
+{
+ if (stream.size() < static_cast<const qint32>(sizeof (quint32)))
+ return IdentifyType::Error;
+
+ QByteArray data = stream.left(sizeof (quint32));
+
+ return identifyData(data.toUInt());
+}
+
+QString FileIdentifier::identifyName(const IdentifyType& type) const
+{
+ switch (type)
+ {
+ case Error:
+ return "file error";
+ case Plain:
+ return "common file";
+ case ZLIB:
+ return "ZLIB compressed file";
+ case VFS:
+ return "Neocron VFS file";
+ case PAK1:
+ return "Neocron PAK file";
+ case PAK2:
+ return "Neocron PAK file (2nd header)";
+ case PAK3:
+ return "Neocron PAK file (3rd header)";
+ default:
+ return "unknown file format";
+ }
+}
+
+QString FileIdentifier::identifyName(const QString& filename) const
+{
+ return identifyName(identify(filename));
+}
+
+QString FileIdentifier::identifyName(const QByteArray& stream) const
+{
+ return identifyName(identify(stream));
+}
+
+// --- protected methods ---
+
+IdentifyType FileIdentifier::identifyData(const quint32& data) const
+{
+ if (data == IdentifyType::VFS)
+ return IdentifyType::VFS;
+
+ if (data == IdentifyType::PAK1)
+ return IdentifyType::PAK1;
+
+ if (reinterpret_cast<const char *>(&data)[0] == 'x')
+ return IdentifyType::ZLIB;
+
+ return IdentifyType::Plain;
+}
--- /dev/null
+#pragma once
+
+#include <QObject>
+#include "common/NCTypes.hxx"
+
+class FileIdentifier : public QObject {
+ Q_OBJECT
+public:
+ // internal typedefs
+ using IdentifyType = NC::Identify::Type;
+
+ // internal constants
+ enum : quint32 {
+ Error = NC::Meta::Error,
+ VFS = NC::Identify::VFS,
+ PAK1 = NC::Identify::PAK1,
+ PAK2 = NC::Identify::PAK2,
+ PAK3 = NC::Identify::PAK3,
+ Plain = NC::Identify::Plain,
+ ZLIB = NC::Identify::ZLIB
+ };
+
+ // constructors and deconstructors
+ FileIdentifier(QObject *parent = 0);
+ FileIdentifier(const FileIdentifier& rhs) = delete;
+ FileIdentifier(const FileIdentifier&& rhs) = delete;
+ virtual ~FileIdentifier();
+
+ // operators
+ FileIdentifier& operator=(const FileIdentifier& rhs) = delete;
+ FileIdentifier& operator=(const FileIdentifier&& rhs) = delete;
+
+ // public methodes
+ IdentifyType identify(const QString& filename) const;
+ IdentifyType identify(const QByteArray& stream) const;
+
+ QString identifyName(const IdentifyType& type) const;
+ QString identifyName(const QString& filename) const;
+ QString identifyName(const QByteArray& stream) const;
+
+protected:
+ // protected methods
+ IdentifyType identifyData(const quint32& data) const;
+};
--- /dev/null
+#include <QDataStream>
+#include "filesystem/NCFile.hxx"
+
+/*
+ * qCompress()/qUncompress() does not behave like the real zlib compress2/uncompress functions,
+ * the Qt functions add a quint32 at the beginning of the QByteArray holding the original size
+ */
+
+// --- internal constants and stuff ---
+
+const quint8 All = NC::FileData::HSize | NC::FileData::Position | NC::FileData::CSize | NC::FileData::OSize
+ | NC::FileData::NameLength | NC::FileData::Name | NC::FileData::CData | NC::FileData::OData;
+
+// --- constructors and deconstructors ---
+
+NCFile::NCFile(QObject *parent,
+ const quint32& hsize, const quint32& pos, const quint32& csize, const quint32& osize,
+ const quint32& nlen, const QString& name, const QByteArray& cdata)
+: QObject(parent), _hsize(hsize), _position(pos), _csize(csize), _osize(osize), _name_length(nlen), _name(name),
+ _cdata(cdata)
+{
+ emit sigFileData(this, All);
+}
+
+NCFile::NCFile(const NCFile& rhs)
+: QObject(rhs.parent()), _hsize(rhs._hsize), _position(rhs._position), _csize(rhs._csize), _osize(rhs._osize),
+ _name_length(rhs._name_length), _name(rhs._name), _cdata(rhs._cdata)
+{
+ emit sigFileData(this, All);
+}
+
+NCFile::NCFile(const NCFile&& rhs)
+: QObject(std::move(rhs.parent())), _hsize(std::move(rhs._hsize)), _position(std::move(rhs._position)),
+ _csize(std::move(rhs._csize)), _osize(std::move(rhs._osize)), _name_length(std::move(rhs._name_length)),
+ _name(std::move(rhs._name)), _cdata(std::move(rhs._cdata))
+{
+ emit sigFileData(this, All);
+}
+
+NCFile::~NCFile()
+{
+}
+
+// --- operators ---
+
+NCFile& NCFile::operator=(const NCFile& rhs)
+{
+ if (this != &rhs)
+ {
+ _hsize = rhs._hsize;
+ _position = rhs._position;
+ _csize = rhs._csize;
+ _osize = rhs._osize;
+ _name_length = rhs._name_length;
+ _name = rhs._name;
+ _cdata = rhs._cdata;
+ }
+
+ return *this;
+}
+
+NCFile& NCFile::operator=(const NCFile&& rhs)
+{
+ if (this != &rhs)
+ {
+ _hsize = std::move(rhs._hsize);
+ _position = std::move(rhs._position);
+ _csize = std::move(rhs._csize);
+ _osize = std::move(rhs._osize);
+ _name_length = std::move(rhs._name_length);
+ _name = std::move(rhs._name);
+ _cdata = std::move(rhs._cdata);
+ }
+
+ return *this;
+}
+
+bool NCFile::operator==(const NCFile& rhs) const
+{
+ return _hsize == rhs._hsize
+ && _position == rhs._position
+ && _csize == rhs._csize
+ && _osize == rhs._osize
+ && _name_length == rhs._name_length
+ && _name == rhs._name
+ && _cdata == rhs._cdata;
+}
+
+bool NCFile::operator!=(const NCFile& rhs) const
+{
+ return !(*this == rhs);
+}
+
+// --- setters and getters ---
+
+void NCFile::setHSize(const quint32& size)
+{
+ _hsize = size;
+}
+
+quint32 NCFile::hSize() const
+{
+ return _hsize;
+}
+
+void NCFile::setPosition(const quint32& pos)
+{
+ _position = pos;
+}
+
+quint32 NCFile::position() const
+{
+ return _position;
+}
+
+void NCFile::setCSize(const quint32& size)
+{
+ _csize = size;
+}
+
+quint32 NCFile::cSize() const
+{
+ return _csize;
+}
+
+void NCFile::setOSize(const quint32& size)
+{
+ _osize = size;
+}
+
+quint32 NCFile::oSize() const
+{
+ return _osize;
+}
+
+void NCFile::setNameLength(const quint32& len)
+{
+ _name_length = len;
+}
+
+quint32 NCFile::nameLength() const
+{
+ return _name_length;
+}
+
+void NCFile::setName(const QString& name)
+{
+ _name = name;
+}
+
+QString NCFile::name() const
+{
+ return _name;
+}
+
+void NCFile::setCData(const QByteArray& data)
+{
+ _cdata = data;
+}
+
+QByteArray NCFile::cData() const
+{
+ return _cdata;
+}
+
+void NCFile::setOData(const QByteArray& data)
+{
+ _cdata = qCompress(data, 9).mid(sizeof (quint32));
+}
+
+QByteArray NCFile::oData() const
+{
+ QByteArray size;
+ QDataStream stream(&size, QIODevice::WriteOnly);
+
+ stream << _csize;
+
+ return qUncompress(size + _cdata);
+}
+
+// --- status methods ---
+
+quint32 NCFile::size() const
+{
+ return HSize + _name_length + _cdata.size();
+}
+
+quint32 NCFile::headerSize() const
+{
+ return HSize;
+}
+
+bool NCFile::valid() const
+{
+ return !(_hsize == Error || _position == Error || _csize == Error || _osize == Error || _name_length == Error
+ || _name.isEmpty() || _cdata.isEmpty());
+}
--- /dev/null
+#pragma once
+
+#include <QObject>
+#include "common/NCTypes.hxx"
+
+class NCFile : public QObject {
+ Q_OBJECT
+signals:
+ void sigFileData(NCFile *file, quint8 type);
+
+public:
+ // internal typedefs
+ enum : quint32 {
+ Error = NC::Meta::Error,
+ HSize = sizeof (quint32) * 5
+ };
+
+ // constructors and deconstructors
+ //explicit NCFile();
+ NCFile(QObject *parent = 0,
+ const quint32& hsize = Error, const quint32& pos = Error, const quint32& csize = Error,
+ const quint32& osize = Error, const quint32& nlen = Error, const QString& name = "",
+ const QByteArray& cdata = "");
+ NCFile(const NCFile& rhs);
+ NCFile(const NCFile&& rhs);
+ virtual ~NCFile();
+
+ // operators
+ NCFile& operator=(const NCFile& rhs);
+ NCFile& operator=(const NCFile&& rhs);
+
+ bool operator==(const NCFile& rhs) const;
+ bool operator!=(const NCFile& rhs) const;
+
+ // setters and getters
+ void setHSize(const quint32& size = 0);
+ quint32 hSize() const;
+
+ void setPosition(const quint32& pos = 0);
+ quint32 position() const;
+
+ void setCSize(const quint32& size = 0);
+ quint32 cSize() const;
+
+ void setOSize(const quint32& size = 0);
+ quint32 oSize() const;
+
+ void setNameLength(const quint32& len = 0);
+ quint32 nameLength() const;
+
+ void setName(const QString& name = "");
+ QString name() const;
+
+ void setCData(const QByteArray& data = "");
+ QByteArray cData() const;
+
+ void setOData(const QByteArray& data = "");
+ QByteArray oData() const;
+
+ // status stuff
+ quint32 size() const;
+ quint32 headerSize() const;
+ bool valid() const;
+
+private:
+ // data fields
+ quint32 _hsize;
+ quint32 _position;
+ quint32 _csize;
+ quint32 _osize;
+ quint32 _name_length;
+ QString _name;
+ QByteArray _cdata;
+};
--- /dev/null
+#include <QFile>
+#include "filesystem/NCFilesystem.hxx"
+#include "filesystem/FileIdentifier.hxx"
+
+// --- internal typedefs ---
+
+using IdentifyType = NC::Identify::Type;
+using ColType = NC::FileData::Type;
+
+// --- internal objects ---
+
+FileIdentifier id;
+
+// --- constructors and deconstructors ---
+
+NCFilesystem::NCFilesystem(QObject *parent)
+: QObject(parent)
+{
+ emit sigFileStatus(0, _files.count(), ColType::None);
+}
+
+NCFilesystem::NCFilesystem(const NCFilesystem& rhs)
+: QObject(rhs.parent()), _files(rhs._files)
+{
+ emit sigFileStatus(0, _files.count(), ColType::None);
+}
+
+NCFilesystem::NCFilesystem(const NCFilesystem&& rhs)
+: QObject(std::move(rhs.parent())), _files(std::move(rhs._files))
+{
+ emit sigFileStatus(0, _files.count(), ColType::None);
+}
+
+NCFilesystem::~NCFilesystem()
+{
+ _files.clear();
+ emit sigFileStatus(0, _files.count(), ColType::None);
+}
+
+// --- operators ---
+
+NCFilesystem& NCFilesystem::operator=(const NCFilesystem& rhs)
+{
+ if (this != &rhs)
+ {
+ _files = rhs._files;
+ emit sigFileStatus(0, _files.count(), ColType::All);
+ }
+
+ return *this;
+}
+
+NCFilesystem& NCFilesystem::operator=(const NCFilesystem&& rhs)
+{
+ if (this != &rhs)
+ {
+ _files = std::move(rhs._files);
+ emit sigFileStatus(0, _files.count(), ColType::All);
+ }
+
+ return *this;
+}
+
+bool NCFilesystem::operator==(const NCFilesystem& rhs) const
+{
+ return _files == rhs._files;
+}
+
+bool NCFilesystem::operator!=(const NCFilesystem& rhs) const
+{
+ return _files != rhs._files;
+}
+
+// --- basic and status methodes ---
+
+quint32 NCFilesystem::count() const
+{
+ return _files.count();
+}
+
+quint32 NCFilesystem::size() const
+{
+ quint32 result = HSize;
+
+ for (auto& f : _files)
+ result += f.size();
+
+ return result;
+}
+
+bool NCFilesystem::valid() const
+{
+ auto it = _files.begin();
+ bool result = true;
+
+ while (result && it != _files.end())
+ {
+ result = result && (*it).valid();
+ ++it;
+ }
+
+ return result;
+}
+
+void NCFilesystem::clear()
+{
+ _files.clear();
+ emit sigFileStatus(0, _files.count(), ColType::None);
+}
+
+QString NCFilesystem::info() const
+{
+ QString result;
+
+ for (qint32 i = 0; i < _files.count(); ++i)
+ {
+ result.append("idx:").append(QString::number(i));
+ result.append(" hs:").append(QString::number(_files[i].hSize()));
+ result.append(" pos:").append(QString::number(_files[i].position()));
+ result.append(" os:").append(QString::number(_files[i].oSize()));
+ result.append(" cs:").append(QString::number(_files[i].cSize()));
+ result.append(" ln:").append(QString::number(_files[i].nameLength()));
+ result.append(" name:'").append(_files[i].name()).append("'").append("\n");
+ }
+
+ return result;
+}
+
+IdentifyType NCFilesystem::fileIdentify(const QString& filename) const
+{
+ return id.identify(filename);
+}
+
+QString NCFilesystem::fileIdentifyName(const IdentifyType& type) const
+{
+ return id.identifyName(type);
+}
+
+QString NCFilesystem::fileIdentifyName(const QString& filename) const
+{
+ return id.identifyName(fileIdentify(filename));
+}
+
+quint32 NCFilesystem::load(const QString& filename)
+{
+ if (fileIdentify(filename) == id.VFS)
+ return vfsLoader(filename, false);
+
+ return Error;
+}
+
+quint32 NCFilesystem::save(const QString& filename) const
+{
+ return vfsSaver(filename);
+}
+
+quint32 NCFilesystem::fileLoad(const QString& filename)
+{
+ switch (fileIdentify(filename))
+ {
+ case id.VFS:
+ return vfsLoader(filename, false);
+ case id.PAK1:
+ return pakLoader(filename, false);
+ case id.Plain:
+ return plainLoader(filename, false);
+ case id.ZLIB:
+ return zlibLoader(filename, false);
+ default:
+ break;
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::fileAdd(const QString& filename)
+{
+ switch (fileIdentify(filename))
+ {
+ case id.VFS:
+ return vfsLoader(filename, true);
+ case id.PAK1:
+ return pakLoader(filename, true);
+ case id.Plain:
+ return plainLoader(filename, true);
+ case id.ZLIB:
+ return zlibLoader(filename, true);
+ default:
+ break;
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::fileAdd(const NCFile& entry)
+{
+ _files.push_back(entry);
+ recalc(_files);
+
+ emit sigFileAdd(_files.back(), _files.count() - 1);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return _files.size();
+}
+
+quint32 NCFilesystem::fileSave(const QString& filename, const QString& name) const
+{
+ return plainSaver(fileGet(name), filename);
+}
+
+quint32 NCFilesystem::fileSave(const QString& filename, const quint32& index) const
+{
+ return plainSaver(fileGet(index), filename);
+}
+
+quint32 NCFilesystem::fileSave(const QString& filename, const QString& name, const IdentifyType& type) const
+{
+ switch (type)
+ {
+ case id.PAK1:
+ return pakSaver(fileGet(name), filename);
+ case id.Plain:
+ return plainSaver(fileGet(name), filename);
+ case id.ZLIB:
+ return zlibSaver(fileGet(name), filename);
+ default:
+ break;
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::fileSave(const QString& filename, const quint32& index, const IdentifyType& type) const
+{
+ switch (type)
+ {
+ case id.PAK1:
+ return pakSaver(fileGet(index), filename);
+ case id.Plain:
+ return plainSaver(fileGet(index), filename);
+ case id.ZLIB:
+ return zlibSaver(fileGet(index), filename);
+ default:
+ break;
+ }
+
+ return Error;
+}
+
+NCFile NCFilesystem::fileGet(const QString& name) const
+{
+ NCFile result;
+
+ for (auto& f : _files)
+ {
+ if (name == f.name())
+ {
+ result = f;
+ break;
+ }
+ }
+
+ return result;
+}
+
+NCFile NCFilesystem::fileGet(const quint32& index) const
+{
+ NCFile result;
+
+ if (index < static_cast<quint32>(_files.count()))
+ result = _files[index];
+
+ return result;
+}
+
+NCFile NCFilesystem::fileReplace(const NCFile& entry, const QString& name)
+{
+ NCFile result;
+
+ if (!entry.valid())
+ return result;
+
+ for (auto& f : _files)
+ {
+ if (name == f.name())
+ {
+ result = f;
+ f = entry;
+
+ emit sigFileReplace(f, _files.indexOf(f));
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ break;
+ }
+ }
+ recalc(_files);
+
+ return result;
+}
+
+NCFile NCFilesystem::fileReplace(const NCFile& entry, const quint32& index)
+{
+ NCFile result;
+
+ if (!entry.valid())
+ return result;
+
+ if (index >= static_cast<quint32>(_files.count()))
+ return result;
+
+ result = _files[index];
+ _files[index] = entry;
+ recalc(_files);
+
+ emit sigFileReplace(_files[index], index);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return result;
+}
+
+NCFile NCFilesystem::fileReplace(const QString& filename, const QString& name)
+{
+ NCFile result;
+
+ if (filename.isEmpty())
+ return result;
+
+ for (auto& f : _files)
+ {
+ if (name == f.name())
+ {
+ NCFilesystem temp;
+
+ temp.fileLoad(filename);
+ if (temp.count())
+ {
+ const quint32 index = _files.indexOf(f);
+ const quint32 added = temp.count();
+
+ result = f;
+ _files.remove(index);
+ while (temp.count())
+ {
+ _files.insert(index, temp.fileGet(temp.count() - 1));
+ temp.fileRemove(temp.count() - 1);
+ }
+ recalc(_files);
+
+ emit sigFileReplace(_files[index], index);
+ for (quint32 i = index; i < (index + added); ++i)
+ emit sigFileAdd(_files[i], i);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+NCFile NCFilesystem::fileReplace(const QString& filename, const quint32& index)
+{
+ NCFile result;
+ NCFilesystem temp;
+
+ if (filename.isEmpty())
+ return result;
+
+ if (index >= static_cast<quint32>(_files.count()))
+ return result;
+
+ temp.fileLoad(filename);
+ if (temp.count())
+ {
+ const quint32 added = temp.count();
+
+ result = _files[index];
+ _files.remove(index);
+ while (temp.count())
+ {
+ _files.insert(index, temp.fileGet(temp.count() - 1));
+ temp.fileRemove(temp.count() - 1);
+ }
+ recalc(_files);
+
+ emit sigFileReplace(_files[index], index);
+ for (quint32 i = (index + 1); i < (index + added); ++i)
+ emit sigFileAdd(_files[i], i);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+ }
+
+ return result;
+}
+
+NCFile NCFilesystem::fileRemove(const QString& name)
+{
+ NCFile result;
+
+ if (name.isEmpty())
+ return result;
+
+ for (auto it = _files.begin(); it != _files.end(); ++it)
+ {
+ if (name == (*it).name())
+ {
+ emit sigFileRemove(_files.indexOf(it));
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ result = *it;
+ _files.erase(it);
+ break;
+ }
+ }
+ recalc(_files);
+
+ return result;
+}
+
+NCFile NCFilesystem::fileRemove(const quint32& index)
+{
+ NCFile result;
+
+ if (index >= static_cast<quint32>(_files.count()))
+ return result;
+
+ result = _files[index];
+ _files.erase(_files.begin() + index);
+ recalc(_files);
+
+ emit sigFileRemove(index);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return result;
+}
+
+// --- internal methodes ---
+
+void NCFilesystem::recalc(QVector<NCFile>& files)
+{
+ quint32 base_offset = 0;
+ quint32 csize_offset = 0;
+
+ for (auto& f : files)
+ base_offset += f.headerSize() + f.nameLength();
+
+ for (auto& f : files)
+ {
+ f.setPosition(base_offset + csize_offset);
+ csize_offset += f.cSize();
+ }
+}
+
+quint32 NCFilesystem::vfsLoader(const QString& filename, const bool add)
+{
+ QFile ifile(filename);
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ QVector<NCFile> files;
+ const quint32 old_size = _files.count();
+ quint32 data = 0;
+ quint32 count = 0;
+ QByteArray stream;
+
+ ifile.seek(sizeof (id.VFS));
+ ifile.read(reinterpret_cast<char *>(&count), sizeof (count));
+
+ for (quint32 i = 0; i < count; ++i)
+ {
+ NCFile entry;
+ quint32 pos = 0;
+
+ // header + name
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setHSize(data);
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setPosition(data);
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setCSize(data);
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setOSize(data);
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setNameLength(data);
+ stream.resize(data);
+ ifile.read(stream.data(), data);
+ stream.truncate(data);
+ entry.setName(stream);
+ // compressed data
+ pos = ifile.pos();
+ ifile.seek(entry.position());
+ stream.resize(entry.cSize());
+ ifile.read(stream.data(), entry.cSize());
+ entry.setCData(stream);
+ ifile.seek(pos);
+
+ files.push_back(entry);
+ }
+ ifile.close();
+
+ if (add)
+ {
+ _files += files;
+ recalc(_files);
+
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+ emit sigFileStatus(old_size, _files.count(), ColType::All);
+ }
+ else
+ {
+ recalc(files);
+ _files = files;
+
+ emit sigFileStatus(0, _files.count(), ColType::None);
+ }
+
+ return _files.count();
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::pakLoader(const QString& filename, const bool add)
+{
+ const quint32 IDSize = sizeof (id.PAK1) + sizeof (id.PAK2) + sizeof (id.PAK3);
+ QFile ifile(filename);
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ quint32 data = 0;
+ QByteArray stream;
+ NCFile entry;
+
+ // header data
+ entry.setPosition(0);
+ entry.setCSize(ifile.size() - IDSize);
+ ifile.seek(IDSize);
+ ifile.read(reinterpret_cast<char *>(&data), sizeof (data));
+ entry.setOSize(data);
+ entry.setNameLength(filename.size() + 1);
+ entry.setName(filename);
+ entry.setHSize(entry.headerSize() + entry.nameLength());
+ // compressed data
+ stream.resize(entry.cSize());
+ ifile.read(stream.data(), entry.cSize());
+ entry.setCData(stream);
+ ifile.close();
+
+ if (!add)
+ _files.clear();
+
+ _files.push_back(entry);
+ recalc(_files);
+
+ emit sigFileAdd(_files.back(), _files.count() - 1);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return _files.count();
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::plainLoader(const QString& filename, const bool add)
+{
+ QFile ifile(filename);
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ QByteArray stream;
+ NCFile entry;
+
+ stream.resize(ifile.size());
+ ifile.read(stream.data(), ifile.size());
+ entry.setOData(stream); // odata compresses stream to cdata
+ entry.setPosition(0);
+ entry.setCSize(entry.cData().size());
+ entry.setOSize(ifile.size());
+ entry.setNameLength(filename.size() + 1);
+ entry.setName(filename);
+ entry.setHSize(entry.headerSize() + entry.nameLength());
+ ifile.close();
+
+ if (!add)
+ _files.clear();
+
+ _files.push_back(entry);
+ recalc(_files);
+
+ emit sigFileAdd(_files.back(), _files.count() - 1);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return _files.count();
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::zlibLoader(const QString& filename, const bool add)
+{
+ QFile ifile(filename);
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ QByteArray stream;
+ NCFile entry;
+
+ stream.resize(ifile.size());
+ ifile.read(stream.data(), ifile.size());
+ entry.setCData(stream);
+ entry.setPosition(0);
+ entry.setCSize(ifile.size());
+ entry.setOSize(entry.oData().size());
+ entry.setNameLength(filename.size() + 1);
+ entry.setName(filename);
+ entry.setHSize(entry.headerSize() + entry.nameLength());
+ ifile.close();
+
+ if (!add)
+ _files.clear();
+
+ _files.push_back(entry);
+ recalc(_files);
+
+ emit sigFileAdd(_files.back(), _files.count() - 1);
+ emit sigFileStatus(0, _files.count(), ColType::Position);
+
+ return _files.count();
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::vfsSaver(const QString& filename) const
+{
+ QFile ofile(filename);
+
+ if (!valid())
+ return Error;
+
+ if (ofile.open(QIODevice::WriteOnly))
+ {
+ quint32 data = 0;
+ const quint32 count = _files.count();
+
+ data = id.VFS;
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ ofile.write(reinterpret_cast<const char *>(&count), sizeof (count));
+
+ for (auto& f : _files)
+ {
+ data = f.hSize();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = f.position();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = f.cSize();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = f.oSize();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = f.nameLength();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ ofile.write(f.name().toStdString().c_str(), f.nameLength());
+ }
+
+ for (auto& f : _files)
+ ofile.write(f.cData());
+
+ ofile.close();
+
+ emit sigFileStatus(0, _files.count() - 1, ColType::None);
+
+ return _files.count();
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::pakSaver(const NCFile& entry, const QString& filename) const
+{
+ QFile ofile(filename);
+
+ if (!entry.valid())
+ return Error;
+
+ if (ofile.open(QIODevice::WriteOnly))
+ {
+ quint32 data = 0;
+
+ data = id.PAK1;
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = id.PAK2;
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = id.PAK3;
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ data = entry.oSize();
+ ofile.write(reinterpret_cast<const char *>(&data), sizeof (data));
+ ofile.write(entry.cData());
+
+ ofile.close();
+
+ return 1;
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::plainSaver(const NCFile& entry, const QString& filename) const
+{
+ QFile ofile(filename);
+
+ if (!entry.valid())
+ return Error;
+
+ if (ofile.open(QIODevice::WriteOnly))
+ {
+ ofile.write(entry.oData());
+ ofile.close();
+
+ return 1;
+ }
+
+ return Error;
+}
+
+quint32 NCFilesystem::zlibSaver(const NCFile& entry, const QString& filename) const
+{
+ QFile ofile(filename);
+
+ if (!entry.valid())
+ return Error;
+
+ if (ofile.open(QIODevice::WriteOnly))
+ {
+ ofile.write(entry.cData());
+ ofile.close();
+
+ return 1;
+ }
+
+ return Error;
+}
--- /dev/null
+#pragma once
+
+/*
+ * the QVector is NOT holding a pointer, this is C++11, we have rvalue references
+ */
+
+#include <QObject>
+#include <QVector>
+#include "common/NCTypes.hxx"
+#include "filesystem/NCFile.hxx"
+
+class NCFilesystem : public QObject {
+ Q_OBJECT
+
+ // interna typedefs
+ using ColType = NC::FileData::Type;
+ using IdentifyType = NC::Identify::Type;
+signals:
+ // signals to report every vfs change
+ void sigFileStatus(quint32 from_row, quint32 to_row, ColType col) const;
+ void sigFileAdd(NCFile& file, quint32 row) const;
+ void sigFileReplace(NCFile& file, quint32 row) const;
+ void sigFileRemove(quint32 row) const;
+
+public:
+ // internal constants
+ enum : quint32 {
+ Error = NC::Meta::Error,
+ HSize = sizeof (quint32) * 2
+ };
+
+ // constructors and deconstructors
+ NCFilesystem(QObject *parent = 0);
+ NCFilesystem(const NCFilesystem& rhs);
+ NCFilesystem(const NCFilesystem&& rhs);
+ virtual ~NCFilesystem();
+
+ // operators
+ NCFilesystem& operator=(const NCFilesystem& rhs);
+ NCFilesystem& operator=(const NCFilesystem&& rhs);
+
+ bool operator==(const NCFilesystem& rhs) const;
+ bool operator!=(const NCFilesystem& rhs) const;
+
+ // basic and status methodes
+ quint32 count() const;
+ quint32 size() const;
+ bool valid() const;
+ void clear();
+ QString info() const;
+
+ IdentifyType fileIdentify(const QString& filename) const;
+ QString fileIdentifyName(const IdentifyType& type) const;
+ QString fileIdentifyName(const QString& filename) const;
+
+ // setters and getters
+ quint32 load(const QString& filename);
+ quint32 save(const QString& filename) const;
+
+ quint32 fileLoad(const QString& filename);
+ quint32 fileAdd(const QString& filename);
+ quint32 fileAdd(const NCFile& entry);
+
+ quint32 fileSave(const QString& filename, const QString& name) const;
+ quint32 fileSave(const QString& filename, const quint32& index) const;
+ quint32 fileSave(const QString& filename, const QString& name, const IdentifyType& type) const;
+ quint32 fileSave(const QString& filename, const quint32& index, const IdentifyType& type) const;
+
+ NCFile fileGet(const QString& name) const;
+ NCFile fileGet(const quint32& index) const;
+
+ NCFile fileReplace(const NCFile& entry, const QString& name);
+ NCFile fileReplace(const NCFile& entry, const quint32& index);
+ NCFile fileReplace(const QString& filename, const QString& name);
+ NCFile fileReplace(const QString& filename, const quint32& index);
+
+ NCFile fileRemove(const QString& name);
+ NCFile fileRemove(const quint32& index);
+
+protected:
+ void recalc(QVector<NCFile>& files);
+
+ quint32 vfsLoader(const QString& filename, const bool add = false);
+ quint32 pakLoader(const QString& filename, const bool add = false);
+ quint32 plainLoader(const QString& filename, const bool add = false);
+ quint32 zlibLoader(const QString& filename, const bool add = false);
+
+ quint32 vfsSaver(const QString& filename) const;
+ quint32 pakSaver(const NCFile& entry, const QString& filename) const;
+ quint32 plainSaver(const NCFile& entry, const QString& filename) const;
+ quint32 zlibSaver(const NCFile& entry, const QString& filename) const;
+
+private:
+ QVector<NCFile> _files;
+};
--- /dev/null
+# apps
+add_executable (test_file test_file.cxx)
+qt5_use_modules (test_file Core)
+target_link_libraries (test_file Filesystem)
+
+add_executable (test_filesystem test_filesystem.cxx)
+qt5_use_modules (test_filesystem Core)
+target_link_libraries (test_filesystem Filesystem)
--- /dev/null
+#include <QFile>
+#include <QTextStream>
+#include "filesystem/NCFile.hxx"
+
+QTextStream out(stdout);
+QTextStream err(stderr);
+
+int main(int argc, char **argv)
+{
+ QFile ifile;
+ NCFile entry;
+ QString filename = argv[0];
+ QByteArray stream;
+
+ if (argc == 2)
+ filename = argv[1];
+
+ ifile.setFileName(filename);
+
+ if (!ifile.exists())
+ {
+ err << "ERROR: unable to open file '" << filename << "'" << endl;
+ return 1;
+ }
+
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ stream.resize(ifile.size());
+ ifile.read(stream.data(), ifile.size());
+ ifile.close();
+ }
+
+ entry.setPosition(17);
+ entry.setOSize(stream.size());
+ entry.setName(filename);
+ entry.setNameLength(filename.size() + 1);
+ entry.setOData(stream);
+ entry.setCSize(entry.cData().size());
+ entry.setHSize(entry.headerSize() + entry.nameLength());
+
+ out << "file: i:" << entry.hSize() << " p:" << entry.position() << " c:" << entry.cSize() << " :o"
+ << entry.oSize() << " l:" << entry.nameLength() << " n:'" << entry.name() << "' -> " << entry.size()
+ << " bytes" << endl;
+
+ return 0;
+}
--- /dev/null
+#include <QTextStream>
+#include "filesystem/NCFilesystem.hxx"
+
+QTextStream out(stdout);
+
+int main(int argc, char **argv)
+{
+ QString filename = argv[0];
+ NCFilesystem vfs;
+
+ if (argc == 2)
+ filename = argv[1];
+
+ out << "loading of '" << filename << "' as VFS was" << (vfs.load(filename) == NC::Meta::Error ? " not " : " ")
+ << "successful" << endl;
+
+ out << "files:" << endl << vfs.info() << endl;
+
+ return 0;
+}
--- /dev/null
+# apps
+add_executable (vfs_tool vfs_tool.cxx)
+qt5_use_modules (vfs_tool Core)
+target_link_libraries (vfs_tool Filesystem)
+
+add_executable (dat_viewer dat_viewer.cxx)
+qt5_use_modules (dat_viewer Core)
+
+add_executable (zcompress zcompress.cxx)
+qt5_use_modules (zcompress Core)
+
+add_executable (zdecompress zdecompress.cxx)
+qt5_use_modules (zdecompress Core)
--- /dev/null
+#include <QFile>
+#include <QTextStream>
+
+QTextStream out(stdout);
+QTextStream err(stderr);
+
+struct Furniture {
+ float coord[3];
+ float rot[3];
+ float scale;
+ quint32 unk1;
+ quint16 mid;
+ quint32 unk2[2];
+ quint16 unk3;
+ quint16 wid;
+ quint16 unk4;
+ qint32 oid;
+ float lower[3];
+ float upper[3];
+} __attribute__((packed));
+
+int main(int argc, char **argv)
+{
+ QFile ifile;
+
+ if (argc == 2)
+ {
+ ifile.setFileName(argv[1]);
+ if (ifile.open(QIODevice::ReadOnly))
+ {
+ QByteArray head;
+
+ while (!ifile.atEnd())
+ {
+ QByteArray head(5 * 4, '\0');
+ quint32 counter = 0;
+ quint32 type = 0;
+ quint32 size = 0;
+
+ ifile.read(reinterpret_cast<char *>(head.data()), head.size());
+ ifile.read(reinterpret_cast<char *>(&type), sizeof (type));
+ ifile.read(reinterpret_cast<char *>(&size), sizeof (size));
+
+ out << "head: 0x" << head.toHex().toUpper() << endl
+ << "type: " << type << endl
+ << "size: " << size << endl;
+
+ while (size)
+ {
+ QByteArray id(2 * 4, '\0');
+ quint32 objtype = 0;
+ quint32 objsize = 0;
+
+ ifile.read(reinterpret_cast<char *>(id.data()), id.size());
+ ifile.read(reinterpret_cast<char *>(&objtype), sizeof (objtype));
+ ifile.read(reinterpret_cast<char *>(&objsize), sizeof (objsize));
+
+ size -= (16 + objsize);
+
+ out << "---------------------------------------------------" << endl
+ << "index: " << counter << endl
+ << "id: 0x" << id.toHex().toUpper() << endl
+ << "objtype: " << objtype << endl
+ << "objsize: " << objsize << endl
+ << "leftsize: " << size << endl;
+
+ switch (objtype)
+ {
+ case 1000003:
+ {
+ Furniture f;
+
+ ifile.read(reinterpret_cast<char *>(&f), sizeof (f));
+
+ out << "furniture!" << endl
+ << "pos: " << f.coord[0] << ", " << f.coord[1] << ", " << f.coord[2] << endl
+ << "rot: " << f.rot[0] << ", " << f.rot[1] << ", " << f.rot[2] << endl
+ << "scale: " << f.scale << endl
+ << "unk1: " << f.unk1 << endl
+ << "model id: " << f.mid << endl
+ << "unk2: " << f.unk2[0] << ", " << f.unk2[1] << endl
+ << "unk3: " << f.unk3 << endl
+ << "world id: " << f.wid << endl
+ << "unk4: " << f.unk4 << endl
+ << "obj id: " << f.oid << endl
+ << "low box: " << f.lower[0] << ", " << f.lower[1] << ", " << f.lower[2] << endl
+ << "up box: " << f.upper[0] << ", " << f.upper[1] << ", " << f.upper[2] << endl;
+
+ break;
+ }
+ default:
+ ifile.seek(ifile.pos() + objsize);
+ }
+ ++counter;
+ }
+ }
+ ifile.close();
+ }
+
+ return 0;
+ }
+
+ out << "usage: " << argv[0] << " <dat file>" << endl;
+
+ return 0;
+}
--- /dev/null
+/*
+ * commands:
+ * - quit/exit : die :D
+ * - ls/list : vfs.info();
+ * - cls/clear : vfs.clear()
+ * - size : vfs.size()
+ * - count : vfs.count()
+ * --------------------------------------------------------------------------
+ * - load <file> : vfs.fileLoad()
+ * - add <file> : vfs.fileAdd()
+ * - remove/delete/rem/del <file/index> : vfs.fileRemove()
+ * - save <filename> : vfs.save()
+ * --------------------------------------------------------------------------
+ * - replace/rep <file/index> <filename> : vfs.fileReplace()
+ * - save <file/index> <filename> : vfs.fileSave()
+ */
+
+#include <QStringList>
+#include <QTextStream>
+#include "filesystem/NCFilesystem.hxx"
+
+QTextStream in(stdin);
+QTextStream out(stdout);
+QTextStream err(stderr);
+
+int main()
+{
+ NCFilesystem vfs;
+ QString input;
+ QStringList list;
+
+ while (true)
+ {
+ out << "(" << vfs.count() << "|" << vfs.size() << ") > " << flush;
+ input = in.readLine();
+ list = input.split(" ");
+
+ switch (list.count())
+ {
+ case 1:
+ {
+ if (list[0].compare("quit", Qt::CaseInsensitive) == 0 || list[0].compare("exit", Qt::CaseInsensitive) == 0)
+ return 0;
+
+ if (list[0].compare("clear", Qt::CaseInsensitive) == 0 || list[0].compare("cls", Qt::CaseInsensitive) == 0)
+ vfs.clear();
+
+ if (list[0].compare("list", Qt::CaseInsensitive) == 0 || list[0].compare("ls", Qt::CaseInsensitive) == 0)
+ out << "list: " << endl << vfs.info() << endl;
+
+ if (list[0].compare("size", Qt::CaseInsensitive) == 0)
+ out << "size: " << vfs.size() << " bytes" << endl;
+
+ if (list[0].compare("count", Qt::CaseInsensitive) == 0)
+ out << "files: " << vfs.count() << endl;
+
+ break;
+ }
+ case 2:
+ {
+ if (list[0].compare("load", Qt::CaseInsensitive) == 0)
+ out << "loading of '" << list[1] << "' " << (vfs.fileLoad(list[1]) != vfs.Error ? "successful" : "failed")
+ << endl;
+
+ if (list[0].compare("add", Qt::CaseInsensitive) == 0)
+ out << "adding of '" << list[1] << "' " << (vfs.fileAdd(list[1]) != vfs.Error ? "successful" : "failed")
+ << endl;
+
+ if (list[0].compare("remove", Qt::CaseInsensitive) == 0 || list[0].compare("delete", Qt::CaseInsensitive) == 0
+ || list[0].compare("rem", Qt::CaseInsensitive) == 0 || list[0].compare("del", Qt::CaseInsensitive) == 0)
+ {
+ bool ok = true;
+ quint32 index = list[1].toUInt(&ok);
+
+ if (ok)
+ out << "removing of file at index " << index << " "
+ << (vfs.fileRemove(index).valid() ? "successful" : "failed") << endl;
+ else
+ out << "removing of file '" << list[1] << "' "
+ << (vfs.fileRemove(list[1]).valid() ? "successful" : "failed") << endl;
+ }
+
+ if (list[0].compare("save", Qt::CaseInsensitive) == 0)
+ out << "saving vfs as '" << list[1] << "' " << (vfs.save(list[1]) != vfs.Error ? "successful" : "failed")
+ << endl;
+
+ break;
+ }
+ case 3:
+ {
+ /*if (list[0].compare("replace", Qt::CaseInsensitive) == 0 || list[0].compare("rep", Qt::CaseInsensitive) == 0)
+ {
+ bool ok = true;
+ quint32 index = list[1].toUInt(&ok);
+
+ if (ok)
+ out << "replacing file at index " << index << " with file '" << list[2] << "' "
+ << (vfs.fileReplace(list[2], index).valid() ? "successful" : "failed") << endl;
+ else
+ out << "replacing file '" << list[1] << " with file " << list[2] << "' "
+ << (vfs.fileReplace(list[2], list[1]).valid() ? "successful" : "failed") << endl;
+ }*/
+
+ if (list[0].compare("save", Qt::CaseInsensitive) == 0)
+ {
+ bool ok = true;
+ quint32 index = list[1].toUInt(&ok);
+
+ if (ok)
+ out << "saving file at index " << index << " as file '" << list[2] << "' "
+ << (vfs.fileSave(list[2], index) != vfs.Error ? "successful" : "failed") << endl;
+ else
+ out << "saving file '" << list[1] << "' as file '" << list[2] << "' "
+ << (vfs.fileSave(list[2], list[1]) != vfs.Error ? "successful" : "failed") << endl;
+ }
+
+ break;
+ }
+ case 4:
+ break;
+ default:
+ err << "error: unknown command '" << input << "'" << endl;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#include <QFile>
+#include <QString>
+#include <QTextStream>
+
+QTextStream out(stdout);
+QTextStream err(stderr);
+
+int main(int argc, char **argv)
+{
+ if (argc == 2)
+ {
+ QFile file(argv[1]);
+
+ if (!file.exists())
+ {
+ err << "ERROR: unable to open file '" << file.fileName() << "'" << endl;
+ return 1;
+ }
+
+ if (file.open(QIODevice::ReadOnly))
+ {
+ QByteArray stream(file.size(), '\0');
+
+ file.read(stream.data(), file.size());
+ file.close();
+
+ if (stream[0] == 'x')
+ {
+ err << "ERROR: file '" << file.fileName() << "' is zlib compressed already" << endl;
+ return 1;
+ }
+
+ stream = qCompress(stream, 9).mid(sizeof (quint32));
+
+ file.setFileName(file.fileName() + ".z");
+ if (file.open(QIODevice::WriteOnly))
+ {
+ file.write(stream);
+ file.close();
+
+ return 0;
+ }
+ else
+ {
+ err << "ERROR: file '" << file.fileName() << "' is not writeable" << endl;
+ return 1;
+ }
+ }
+ else
+ {
+ err << "ERROR: file '" << file.fileName() << "' is not readable" << endl;
+ return 1;
+ }
+ }
+
+ out << "usage: " << argv[0] << " <file to compress>" << endl;
+
+ return 0;
+}
--- /dev/null
+#include <QFile>
+#include <QString>
+#include <QTextStream>
+
+QTextStream out(stdout);
+QTextStream err(stderr);
+
+int main(int argc, char **argv)
+{
+ if (argc == 2)
+ {
+ QFile file(argv[1]);
+
+ if (!file.exists())
+ {
+ err << "ERROR: unable to open file '" << file.fileName() << "'" << endl;
+ return 1;
+ }
+
+ if (file.open(QIODevice::ReadOnly))
+ {
+ // black maigc ;-) naaa, we need a quint32 at the beginning of the zlib stream to get qUncompress()
+ // to eat it
+ const quint32 tmp_size = sizeof (quint32);
+ QByteArray stream(file.size() + tmp_size, '\0');
+
+ file.read(stream.data() + 4, file.size());
+ file.close();
+
+ if (stream[tmp_size] != 'x')
+ {
+ err << "ERROR: file '" << file.fileName() << "' is not zlib compressed" << endl;
+ return 1;
+ }
+
+ stream = qUncompress(stream);
+
+ file.setFileName(file.fileName() + ".decompressed");
+ if (file.open(QIODevice::WriteOnly))
+ {
+ file.write(stream);
+ file.close();
+
+ return 0;
+ }
+ else
+ {
+ err << "ERROR: file '" << file.fileName() << "' is not writeable" << endl;
+ return 1;
+ }
+ }
+ else
+ {
+ err << "ERROR: file '" << file.fileName() << "' is not readable" << endl;
+ return 1;
+ }
+ }
+
+ out << "usage: " << argv[0] << " <.z file to decompress>" << endl;
+
+ return 0;
+}