├── .gitattributes ├── resources └── oxe_icon_trans.ico ├── resources.qrc ├── Source ├── main.cpp ├── Decryptors │ ├── INosDecryptor.h │ ├── NosZlibDecryptor.cpp │ ├── NosZlibDecryptor.h │ ├── NosTextOthersFileDecryptor.h │ ├── NosTextOthersFileDecryptor.cpp │ ├── NosTextDatFileDecryptor.h │ └── NosTextDatFileDecryptor.cpp ├── Ui │ ├── FileInfo.h │ ├── OnexTreeText.h │ ├── SingleTextFilePreview.cpp │ ├── OnexNStcData.h │ ├── OnexNS4BbData.h │ ├── OnexTreeText.cpp │ ├── SingleTextFilePreview.h │ ├── OnexNSipData.h │ ├── OnexNStpData.h │ ├── OnexTreeZlibItem.h │ ├── SingleTextFilePreview.ui │ ├── SingleImagePreview.ui │ ├── FileInfo.cpp │ ├── OnexTreeImage.h │ ├── SingleImagePreview.h │ ├── OnexNSipData.cpp │ ├── OnexTreeItem.h │ ├── OnexNS4BbData.cpp │ ├── OnexNStcData.cpp │ ├── OnexTreeZlibItem.cpp │ ├── SingleImagePreview.cpp │ ├── OnexNStpData.cpp │ ├── OnexTreeImage.cpp │ ├── FileInfo.ui │ └── OnexTreeItem.cpp ├── Openers │ ├── INosFileOpener.h │ ├── NosTextOpener.h │ ├── INosFileOpener.cpp │ ├── NosZlibOpener.h │ ├── NosTextOpener.cpp │ └── NosZlibOpener.cpp ├── NosEnumTypes.h ├── ImageConverter.h ├── MainWindow.h ├── mainwindow.ui ├── MainWindow.cpp └── ImageConverter.cpp ├── .gitignore ├── README.MD ├── LICENSE └── OnexExplorer.pro /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /resources/oxe_icon_trans.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OnexTale/OnexExplorer/HEAD/resources/oxe_icon_trans.ico -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resources/oxe_icon_trans.ico 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /Source/Decryptors/INosDecryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef INOSDECRYPTOR_H 2 | #define INOSDECRYPTOR_H 3 | #include 4 | 5 | class INosDecryptor 6 | { 7 | public: 8 | virtual QByteArray encrypt(QByteArray& array) = 0; 9 | virtual QByteArray decrypt(QByteArray& array) = 0; 10 | }; 11 | 12 | #endif // INOSDECRYPTOR_H 13 | -------------------------------------------------------------------------------- /Source/Decryptors/NosZlibDecryptor.cpp: -------------------------------------------------------------------------------- 1 | #include "NosZlibDecryptor.h" 2 | 3 | NosZlibDecryptor::NosZlibDecryptor() 4 | { 5 | 6 | } 7 | 8 | QByteArray NosZlibDecryptor::encrypt(QByteArray &array) 9 | { 10 | return qCompress(array, 1); 11 | } 12 | 13 | QByteArray NosZlibDecryptor::decrypt(QByteArray &array) 14 | { 15 | return qUncompress(array); 16 | } 17 | -------------------------------------------------------------------------------- /Source/Decryptors/NosZlibDecryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSZLIBDECRYPTOR_H 2 | #define NOSZLIBDECRYPTOR_H 3 | #include "INosDecryptor.h" 4 | #include 5 | 6 | class NosZlibDecryptor 7 | { 8 | public: 9 | NosZlibDecryptor(); 10 | virtual QByteArray encrypt(QByteArray& array); 11 | virtual QByteArray decrypt(QByteArray& array); 12 | }; 13 | 14 | #endif // NOSZLIBDECRYPTOR_H 15 | -------------------------------------------------------------------------------- /Source/Ui/FileInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef FILEINFO_H 2 | #define FILEINFO_H 3 | 4 | #include 5 | #include "OnexTreeItem.h" 6 | 7 | namespace Ui { 8 | class FileInfo; 9 | } 10 | 11 | class FileInfo : public QDialog 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit FileInfo(OnexTreeItem* item, QWidget *parent = 0); 17 | ~FileInfo(); 18 | 19 | private: 20 | Ui::FileInfo *ui; 21 | }; 22 | 23 | #endif // FILEINFO_H 24 | -------------------------------------------------------------------------------- /Source/Decryptors/NosTextOthersFileDecryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSTEXTOTHERSFILEDECRYPTOR_H 2 | #define NOSTEXTOTHERSFILEDECRYPTOR_H 3 | #include "INosDecryptor.h" 4 | 5 | class NosTextOthersFileDecryptor : public INosDecryptor 6 | { 7 | public: 8 | NosTextOthersFileDecryptor(); 9 | virtual QByteArray encrypt(QByteArray& array); 10 | virtual QByteArray decrypt(QByteArray& array); 11 | }; 12 | 13 | #endif // NOSTEXTOTHERSFILEDECRYPTOR_H 14 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeText.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXTREETEXT_H 2 | #define ONEXTREETEXT_H 3 | #include "OnexTreeItem.h" 4 | 5 | class OnexTreeText : public OnexTreeItem 6 | { 7 | private: 8 | int fileNmber; 9 | int isDat; 10 | public: 11 | OnexTreeText(QString name, int fileNumber = 0, int isDat = 0, QByteArray content = QByteArray()); 12 | virtual QWidget* onClicked() override; 13 | 14 | virtual ~OnexTreeText(); 15 | }; 16 | 17 | #endif // ONEXTREETEXT_H 18 | -------------------------------------------------------------------------------- /Source/Ui/SingleTextFilePreview.cpp: -------------------------------------------------------------------------------- 1 | #include "SingleTextFilePreview.h" 2 | #include "ui_SingleTextFilePreview.h" 3 | 4 | SingleTextFilePreview::SingleTextFilePreview(QByteArray &item, QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::SingleTextFilePreview) 7 | { 8 | ui->setupUi(this); 9 | ui->plainTextEdit->appendPlainText(QString::fromLocal8Bit(item)); 10 | } 11 | 12 | SingleTextFilePreview::~SingleTextFilePreview() 13 | { 14 | delete ui; 15 | } 16 | -------------------------------------------------------------------------------- /Source/Decryptors/NosTextOthersFileDecryptor.cpp: -------------------------------------------------------------------------------- 1 | #include "NosTextOthersFileDecryptor.h" 2 | 3 | NosTextOthersFileDecryptor::NosTextOthersFileDecryptor() 4 | { 5 | 6 | } 7 | 8 | QByteArray NosTextOthersFileDecryptor::encrypt(QByteArray &array) 9 | { 10 | return QByteArray(); 11 | } 12 | 13 | QByteArray NosTextOthersFileDecryptor::decrypt(QByteArray &array) 14 | { 15 | QByteArray result; 16 | 17 | for (auto& byte : array) 18 | result.push_back(byte ^ 0x1); 19 | 20 | return result; 21 | } 22 | -------------------------------------------------------------------------------- /Source/Openers/INosFileOpener.h: -------------------------------------------------------------------------------- 1 | #ifndef INOSFILEOPENER_H 2 | #define INOSFILEOPENER_H 3 | #include 4 | #include 5 | #include "../Ui/OnexTreeItem.h" 6 | 7 | class INosFileOpener 8 | { 9 | protected: 10 | int readNextInt(QFile& file); 11 | QByteArray writeNextInt(int number); 12 | QString neatFileName(QString fileName); 13 | public: 14 | virtual OnexTreeItem* decrypt(QFile& file) = 0; 15 | virtual QByteArray encrypt(OnexTreeItem* item) = 0; 16 | }; 17 | 18 | #endif // INOSFILEOPENER_H 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *build-* 27 | 28 | # QtCreator 29 | 30 | *.autosave 31 | 32 | # QtCtreator Qml 33 | *.qmlproject.user 34 | *.qmlproject.user.* 35 | 36 | # QtCtreator CMake 37 | CMakeLists.txt.user* 38 | 39 | # Windows trash 40 | *.db -------------------------------------------------------------------------------- /Source/Decryptors/NosTextDatFileDecryptor.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSTEXTFILEDECRYPTOR_H 2 | #define NOSTEXTFILEDECRYPTOR_H 3 | #include 4 | #include "INosDecryptor.h" 5 | 6 | class NosTextDatFileDecryptor : public INosDecryptor 7 | { 8 | private: 9 | const std::array cryptoArray; 10 | public: 11 | NosTextDatFileDecryptor(); 12 | virtual QByteArray encrypt(QByteArray& array); 13 | virtual QByteArray decrypt(QByteArray& array); 14 | ~NosTextDatFileDecryptor(); 15 | }; 16 | 17 | #endif // NOSTEXTFILEDECRYPTOR_H 18 | -------------------------------------------------------------------------------- /Source/Ui/OnexNStcData.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXNSTCDATA_H 2 | #define ONEXNSTCDATA_H 3 | #include "OnexTreeImage.h" 4 | 5 | class OnexNStcData : public OnexTreeImage 6 | { 7 | public: 8 | OnexNStcData(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 9 | 10 | virtual QImage getImage() override; 11 | virtual ImageResolution getResolution() override; 12 | 13 | virtual ~OnexNStcData(); 14 | 15 | private slots: 16 | virtual void onReplace() override; 17 | }; 18 | 19 | #endif // ONEXNSTCDATA_H 20 | -------------------------------------------------------------------------------- /Source/Ui/OnexNS4BbData.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXNS4BBDATA_H 2 | #define ONEXNS4BBDATA_H 3 | #include "OnexTreeImage.h" 4 | 5 | 6 | class OnexNS4BbData : public OnexTreeImage 7 | { 8 | public: 9 | OnexNS4BbData(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 10 | 11 | virtual QImage getImage() override; 12 | virtual ImageResolution getResolution() override; 13 | 14 | virtual ~OnexNS4BbData(); 15 | 16 | private slots: 17 | virtual void onReplace() override; 18 | }; 19 | 20 | #endif // ONEXNS4BBDATA_H 21 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeText.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexTreeText.h" 2 | #include "SingleTextFilePreview.h" 3 | 4 | OnexTreeText::OnexTreeText(QString name, int fileNumber, int isDat, QByteArray content) : OnexTreeItem(name, content) 5 | { 6 | this->fileNmber = fileNumber; 7 | this->isDat = isDat; 8 | } 9 | 10 | QWidget *OnexTreeText::onClicked() 11 | { 12 | SingleTextFilePreview* window = new SingleTextFilePreview(content); 13 | window->setWindowTitle(this->getName()); 14 | 15 | return window; 16 | } 17 | 18 | OnexTreeText::~OnexTreeText() 19 | { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Source/Ui/SingleTextFilePreview.h: -------------------------------------------------------------------------------- 1 | #ifndef SINGLETEXTFILEPREVIEW_H 2 | #define SINGLETEXTFILEPREVIEW_H 3 | 4 | #include 5 | #include 6 | #include "OnexTreeText.h" 7 | 8 | namespace Ui { 9 | class SingleTextFilePreview; 10 | } 11 | 12 | class SingleTextFilePreview : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit SingleTextFilePreview(QByteArray &item, QWidget *parent = 0); 18 | ~SingleTextFilePreview(); 19 | 20 | private: 21 | Ui::SingleTextFilePreview *ui; 22 | }; 23 | 24 | #endif // SINGLETEXTFILEPREVIEW_H 25 | -------------------------------------------------------------------------------- /Source/Ui/OnexNSipData.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXNSIPDATA_H 2 | #define ONEXNSIPDATA_H 3 | #include "OnexTreeImage.h" 4 | 5 | class OnexNSipData : public OnexTreeImage 6 | { 7 | private: 8 | 9 | public: 10 | OnexNSipData(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 11 | 12 | virtual QImage getImage() override; 13 | virtual ImageResolution getResolution() override; 14 | virtual ~OnexNSipData(); 15 | 16 | private slots: 17 | virtual void onReplace() override; 18 | 19 | 20 | }; 21 | 22 | #endif // ONEXNSIPDATA_H 23 | -------------------------------------------------------------------------------- /Source/Ui/OnexNStpData.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXNSTPDATA_H 2 | #define ONEXNSTPDATA_H 3 | #include "OnexTreeImage.h" 4 | 5 | class OnexNStpData : public OnexTreeImage 6 | { 7 | public: 8 | OnexNStpData(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 9 | 10 | int getFormat(); 11 | virtual QImage getImage() override; 12 | virtual ImageResolution getResolution() override; 13 | 14 | virtual ~OnexNStpData(); 15 | 16 | private slots: 17 | virtual void onReplace() override; 18 | }; 19 | 20 | #endif // ONEXNSTPDATA_H 21 | -------------------------------------------------------------------------------- /Source/Openers/NosTextOpener.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSTEXTOPENER_H 2 | #define NOSTEXTOPENER_H 3 | 4 | #include 5 | #include 6 | #include "INosFileOpener.h" 7 | #include "../Decryptors/NosTextDatFileDecryptor.h" 8 | #include "../Ui/OnexTreeText.h" 9 | 10 | class NosTextOpener : public QObject, INosFileOpener 11 | { 12 | Q_OBJECT 13 | private: 14 | NosTextDatFileDecryptor datDecryptor; 15 | public: 16 | NosTextOpener(); 17 | virtual OnexTreeItem* decrypt(QFile& file); 18 | virtual QByteArray encrypt(OnexTreeItem* item); 19 | 20 | }; 21 | 22 | #endif // NOSTEXTOPENER_H 23 | -------------------------------------------------------------------------------- /Source/Openers/INosFileOpener.cpp: -------------------------------------------------------------------------------- 1 | #include "INosFileOpener.h" 2 | 3 | int INosFileOpener::readNextInt(QFile &file) 4 | { 5 | return qFromLittleEndian(reinterpret_cast(file.read(4).data())); 6 | } 7 | 8 | QByteArray INosFileOpener::writeNextInt(int number) 9 | { 10 | QByteArray writeArray; 11 | writeArray.resize(4); 12 | qToLittleEndian(number, reinterpret_cast(writeArray.data())); 13 | return writeArray; 14 | } 15 | 16 | QString INosFileOpener::neatFileName(QString fileName) 17 | { 18 | QStringList list = fileName.split("/"); 19 | 20 | if (list.empty()) 21 | return fileName; 22 | 23 | return list.back(); 24 | } 25 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeZlibItem.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXTREEZLIBITEM_H 2 | #define ONEXTREEZLIBITEM_H 3 | #include "OnexTreeItem.h" 4 | #include "../Openers/NosZlibOpener.h" 5 | 6 | class OnexTreeZlibItem : public OnexTreeItem 7 | { 8 | protected: 9 | int id; 10 | int creationDate; 11 | bool compressed; 12 | NosZlibOpener* opener; 13 | public: 14 | OnexTreeZlibItem(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 15 | virtual QWidget *onClicked() override; 16 | virtual void onExporAsOriginal() override; 17 | int getId(); 18 | int getCreationDate(); 19 | bool isCompressed(); 20 | virtual ~OnexTreeZlibItem(); 21 | }; 22 | 23 | #endif // ONEXTREEZLIBITEM_H 24 | -------------------------------------------------------------------------------- /Source/Ui/SingleTextFilePreview.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SingleTextFilePreview 4 | 5 | 6 | 7 | 0 8 | 0 9 | 531 10 | 421 11 | 12 | 13 | 14 | Text 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Source/Ui/SingleImagePreview.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SingleImagePreview 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Image 15 | 16 | 17 | 18 | 19 | 20 | TextLabel 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # OnexExplorer # 2 | OnexExplorer is an open-source tool for unpacking and repacking .NOS data files from game called NosTale. It can open almost all .NOS files and show the data stored in them. Our software works on Qt 5.5+ 3 | 4 | [](https://discord.gg/VARTAuY) 5 | 6 | ## Currently supported files ## 7 | - NSipData 8 | - NStpData, NStpeData, NStpuData 9 | - all lang (txt&dat, lst is NOT supported yet) 10 | - NStcData 11 | - NS4BbData 12 | Other files will be added in future updates. 13 | 14 | ## License ## 15 | Our project is based on **Boost Software License**: 16 | > [LICENSE](https://github.com/OnexTale/OnexExplorer/blob/master/LICENSE) 17 | 18 | ## Installation ## 19 | 1. Compile given sourcecode using Qt 5.5+ 20 | 2. Move required Qt DLL's to EXE's location 21 | 3. Run the program 22 | -------------------------------------------------------------------------------- /Source/NosEnumTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSENUMTYPES_H 2 | #define NOSENUMTYPES_H 3 | 4 | #define PCHPKG 1 5 | #define NStuData 2 6 | #define NStkData 3 7 | #define NStcData 5 8 | #define NStgData 6 9 | #define NStpData 7 10 | #define NStsData 9 11 | #define NStgeData 10 12 | #define NStpeData 11 13 | #define NStpuData 12 14 | #define NSpcData 13 15 | #define NSppData 14 16 | #define NSpmData 15 17 | #define NSmcData 16 18 | #define NSmpData 17 19 | #define NSedData 20 20 | #define NSemData 21 21 | #define NSesData 22 22 | #define NSeffData 23 23 | #define NSipData 24 24 | #define NSgrdData 26 25 | 26 | #define NS4BbData 101 //temporary 27 | #define NSipData2006 103 28 | 29 | /* 30 | #define NSpnData 31 | #define NSmnData 32 | 33 | #define PCHPKG_DATA 34 | 35 | #define NScliData 36 | #define NSetcData 37 | #define NSlangData 38 | #define NSgtdData 39 | */ 40 | 41 | 42 | #endif // NOSENUMTYPES_H 43 | -------------------------------------------------------------------------------- /Source/Ui/FileInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "FileInfo.h" 2 | #include "ui_FileInfo.h" 3 | 4 | FileInfo::FileInfo(OnexTreeItem *item, QWidget *parent) : 5 | QDialog(parent, Qt::WindowCloseButtonHint), 6 | ui(new Ui::FileInfo) 7 | { 8 | ui->setupUi(this); 9 | 10 | /* 11 | ui->name->setText(item->getName()); 12 | ui->header->setText(QString::number(item->getHeaderValue())); 13 | ui->sizeb->setText(QString::number(item->getContent().size())); 14 | int timestamp = item->getTimestamp(); 15 | int year = (timestamp & 0xFFFF0000) >> 0x10; 16 | int month = (timestamp & 0xFF00) >> 0x08; 17 | int day = timestamp & 0xFF; 18 | 19 | QString date = QString("%1/%2/%3").arg(day, 2, 16, QChar('0')).arg(month, 2, 16, QChar('0')).arg(year, 4, 16, QChar('0')); 20 | ui->date->setText(date); 21 | */ 22 | } 23 | 24 | FileInfo::~FileInfo() 25 | { 26 | delete ui; 27 | } 28 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeImage.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXTREEIMAGE_H 2 | #define ONEXTREEIMAGE_H 3 | #include "OnexTreeZlibItem.h" 4 | #include "SingleImagePreview.h" 5 | 6 | struct ImageResolution 7 | { 8 | int x; 9 | int y; 10 | }; 11 | 12 | class OnexTreeImage : public OnexTreeZlibItem 13 | { 14 | Q_OBJECT 15 | protected: 16 | bool hasGoodResolution(int x, int y); 17 | QImage importQImageFromSelectedUserFile(); 18 | public: 19 | OnexTreeImage(QString name, QByteArray content, NosZlibOpener* opener, int id, int creationDate, bool compressed); 20 | 21 | virtual QWidget *onClicked() override; 22 | virtual QImage getImage() = 0; 23 | virtual ImageResolution getResolution() = 0; 24 | 25 | private slots: 26 | virtual void onExportAll(); 27 | virtual void onExportSingle(); 28 | 29 | signals: 30 | void replaceSignal(QImage newImage); 31 | 32 | }; 33 | 34 | #endif // ONEXTREEIMAGE_H 35 | -------------------------------------------------------------------------------- /Source/Openers/NosZlibOpener.h: -------------------------------------------------------------------------------- 1 | #ifndef NOSZLIBOPENER_H 2 | #define NOSZLIBOPENER_H 3 | #include "INosFileOpener.h" 4 | #include "../NosEnumTypes.h" 5 | #include "../Decryptors/NosZlibDecryptor.h" 6 | #include "../ImageConverter.h" 7 | #include 8 | #include 9 | class NosZlibOpener : public INosFileOpener 10 | { 11 | private: 12 | static const int NOS_HEADER_SIZE = 0x10; 13 | NosZlibDecryptor decryptor; 14 | ImageConverter imageConverter; 15 | QByteArray toBigEndian(qint32 value); 16 | int getNTHeaderNumber(QByteArray& array); 17 | 18 | OnexTreeItem *createItemFromHeader(int header, QString name, QByteArray &array, int fileId = 0, int creationDate = 0, bool compressed = 0); 19 | public: 20 | NosZlibOpener(); 21 | ImageConverter &getImageConverter(); 22 | virtual OnexTreeItem* decrypt(QFile& file); 23 | virtual QByteArray encrypt(OnexTreeItem* item); 24 | }; 25 | 26 | #endif // NOSZLIBOPENER_H 27 | -------------------------------------------------------------------------------- /Source/Ui/SingleImagePreview.h: -------------------------------------------------------------------------------- 1 | #ifndef SINGLEIMAGEPREVIEW_H 2 | #define SINGLEIMAGEPREVIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "../ImageConverter.h" 12 | #include "../NosEnumTypes.h" 13 | 14 | namespace Ui { 15 | class SingleImagePreview; 16 | } 17 | 18 | class SingleImagePreview : public QWidget 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit SingleImagePreview(QImage image, QWidget *parent = 0); 24 | ~SingleImagePreview(); 25 | private: 26 | Ui::SingleImagePreview *ui; 27 | ImageConverter converter; 28 | qint16 byteArrayToShort(QByteArray array); 29 | void showWarningMessage(); 30 | private slots: 31 | void showCustomMenu(const QPoint &pos); 32 | void exportImage(); 33 | void onReplaced(QImage newImage); 34 | }; 35 | 36 | #endif // SINGLEIMAGEPREVIEW_H 37 | -------------------------------------------------------------------------------- /Source/Openers/NosTextOpener.cpp: -------------------------------------------------------------------------------- 1 | #include "NosTextOpener.h" 2 | 3 | NosTextOpener::NosTextOpener() 4 | { 5 | 6 | } 7 | 8 | OnexTreeItem *NosTextOpener::decrypt(QFile &file) 9 | { 10 | file.seek(0); 11 | 12 | OnexTreeText *item = new OnexTreeText(neatFileName(file.fileName())); 13 | int fileAmount = readNextInt(file); 14 | 15 | for (int i = 0; i < fileAmount; ++i) 16 | { 17 | int fileNumber = readNextInt(file); 18 | int stringNameSize = readNextInt(file); 19 | QString stringName = file.read(stringNameSize); 20 | int isDat = readNextInt(file); 21 | int fileSize = readNextInt(file); 22 | QByteArray fileContent = file.read(fileSize); 23 | 24 | QByteArray decryptedArray = datDecryptor.decrypt(fileContent); 25 | 26 | item->addChild(new OnexTreeText(stringName, fileNumber, isDat, decryptedArray)); 27 | } 28 | 29 | return item; 30 | } 31 | 32 | QByteArray NosTextOpener::encrypt(OnexTreeItem *item) 33 | { 34 | return QByteArray(); 35 | } 36 | -------------------------------------------------------------------------------- /Source/ImageConverter.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAGECONVERTER_H 2 | #define IMAGECONVERTER_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class ImageConverter 9 | { 10 | private: 11 | QMap colors; 12 | public: 13 | QImage convertGBAR4444(QByteArray& array, int width, int height, int startByte = 0); 14 | QImage convertBGRA8888(QByteArray& array, int width, int height, int startByte = 0); 15 | QImage convertARGB555(QByteArray& array, int width, int height, int startByte = 0); 16 | QImage convertNSTC(QByteArray& array, int width, int height, int startByte = 0); 17 | QImage convertBGRA8888_INTERLACED(QByteArray& array, int width, int height, int startByte = 0); 18 | QImage convertBARG4444(QByteArray& array, int width, int height, int startByte = 0); 19 | QByteArray toGBAR4444(QImage& image); 20 | QByteArray toNSTC(QImage& image); 21 | QByteArray toBGRA8888(QImage& image); 22 | QByteArray toARGB555(QImage& image); 23 | QByteArray toBGRA8888_INTERLACED(QImage& image); 24 | QByteArray toBARG4444(QImage& image); 25 | ImageConverter(); 26 | }; 27 | 28 | #endif // IMAGECONVERTER_H 29 | -------------------------------------------------------------------------------- /Source/Ui/OnexNSipData.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexNSipData.h" 2 | 3 | OnexNSipData::OnexNSipData(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeImage(name, content, opener, id, creationDate, compressed) 5 | { 6 | 7 | } 8 | 9 | QImage OnexNSipData::getImage() 10 | { 11 | ImageResolution resolution = this->getResolution(); 12 | 13 | return opener->getImageConverter().convertGBAR4444(content, resolution.x, resolution.y, 13); 14 | } 15 | 16 | ImageResolution OnexNSipData::getResolution() 17 | { 18 | int x = fromLittleEndianToShort(content.mid(1, 2)); 19 | int y = fromLittleEndianToShort(content.mid(3, 2)); 20 | 21 | return ImageResolution{x, y}; 22 | } 23 | 24 | void OnexNSipData::onReplace() 25 | { 26 | QImage image = importQImageFromSelectedUserFile(); 27 | if (image.isNull()) 28 | return; 29 | 30 | if (!hasGoodResolution(image.width(), image.height())) 31 | return; 32 | 33 | QByteArray newContent; 34 | newContent.push_back(content.mid(0, 13)); 35 | newContent.push_back(opener->getImageConverter().toGBAR4444(image)); 36 | 37 | content = newContent; 38 | 39 | emit OnexTreeImage::replaceSignal(this->getImage()); 40 | } 41 | 42 | OnexNSipData::~OnexNSipData() 43 | { 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeItem.h: -------------------------------------------------------------------------------- 1 | #ifndef ONEXTREEITEM_H 2 | #define ONEXTREEITEM_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class OnexTreeItem : public QObject, public QTreeWidgetItem 11 | { 12 | Q_OBJECT 13 | protected: 14 | QByteArray content; 15 | QString name; 16 | 17 | QString getSelectedDirectory(); 18 | QString getSaveDirectory(QString name, QString filter); 19 | QString getOpenDirectory(QString filter); 20 | QMessageBox getMsgBox(QString title, QString message, QMessageBox::Icon icon); 21 | public: 22 | OnexTreeItem(QString name, QByteArray content = QByteArray()); 23 | QByteArray getContent(); 24 | bool hasParent(); 25 | short fromLittleEndianToShort(QByteArray array); 26 | int getContentSize(); 27 | 28 | virtual QString getName(); 29 | virtual QMenu* getContextMenu(); 30 | virtual QWidget *onClicked() = 0; 31 | virtual ~OnexTreeItem(); 32 | 33 | public slots: 34 | virtual void onExportAll(); 35 | virtual void onExportSingle(); 36 | virtual void onExporSingleRaw(); 37 | virtual void onExporAsOriginal(); 38 | virtual void onReplace(); 39 | virtual void actionClose(); 40 | }; 41 | 42 | #endif // ONEXTREEITEM_H 43 | -------------------------------------------------------------------------------- /Source/Ui/OnexNS4BbData.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexNS4BbData.h" 2 | 3 | OnexNS4BbData::OnexNS4BbData(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeImage(name, content, opener, id, creationDate, compressed) 5 | { 6 | 7 | } 8 | 9 | QImage OnexNS4BbData::getImage() 10 | { 11 | ImageResolution resolution = this->getResolution(); 12 | 13 | return opener->getImageConverter().convertBGRA8888_INTERLACED(content, resolution.x, resolution.y, 4); 14 | } 15 | 16 | ImageResolution OnexNS4BbData::getResolution() 17 | { 18 | int x = fromLittleEndianToShort(content.mid(0, 2)); 19 | int y = fromLittleEndianToShort(content.mid(2, 2)); 20 | 21 | return ImageResolution{x, y}; 22 | } 23 | 24 | void OnexNS4BbData::onReplace() 25 | { 26 | QImage image = importQImageFromSelectedUserFile(); 27 | if (image.isNull()) 28 | return; 29 | 30 | if (!hasGoodResolution(image.width(), image.height())) 31 | return; 32 | 33 | QByteArray newContent; 34 | newContent.push_back(content.mid(0, 4)); 35 | newContent.push_back(opener->getImageConverter().toBGRA8888_INTERLACED(image)); 36 | 37 | content = newContent; 38 | 39 | emit OnexTreeImage::replaceSignal(this->getImage()); 40 | } 41 | 42 | OnexNS4BbData::~OnexNS4BbData() 43 | { 44 | 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Source/Ui/OnexNStcData.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexNStcData.h" 2 | 3 | OnexNStcData::OnexNStcData(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeImage(name, content, opener, id, creationDate, compressed) 5 | { 6 | 7 | } 8 | 9 | QImage OnexNStcData::getImage() 10 | { 11 | ImageResolution resolution = this->getResolution(); 12 | 13 | return opener->getImageConverter().convertNSTC(content, resolution.x, resolution.y, 4); 14 | } 15 | 16 | ImageResolution OnexNStcData::getResolution() 17 | { 18 | int x = fromLittleEndianToShort(content.mid(0, 2)); 19 | int y = fromLittleEndianToShort(content.mid(2, 2)); 20 | 21 | return ImageResolution{x, y}; 22 | } 23 | 24 | void OnexNStcData::onReplace() 25 | { 26 | QImage image = importQImageFromSelectedUserFile(); 27 | if (image.isNull()) 28 | return; 29 | 30 | image = image.scaled(image.width()/2, image.height()/2); 31 | 32 | if (!hasGoodResolution(image.width(), image.height())) 33 | { 34 | qDebug() << "NStc wrong resolution"; 35 | return; 36 | } 37 | 38 | QByteArray newContent; 39 | newContent.push_back(content.mid(0, 4)); 40 | newContent.push_back(opener->getImageConverter().toNSTC(image)); 41 | 42 | content = newContent; 43 | 44 | emit OnexTreeImage::replaceSignal(this->getImage()); 45 | } 46 | 47 | OnexNStcData::~OnexNStcData() 48 | { 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeZlibItem.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexTreeZlibItem.h" 2 | 3 | OnexTreeZlibItem::OnexTreeZlibItem(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeItem(name, content), 5 | id(id), 6 | creationDate(creationDate), 7 | compressed(compressed), 8 | opener(opener) 9 | { 10 | 11 | } 12 | 13 | QWidget *OnexTreeZlibItem::onClicked() 14 | { 15 | return nullptr; 16 | } 17 | 18 | void OnexTreeZlibItem::onExporAsOriginal() 19 | { 20 | QString fileName = getSaveDirectory(this->getName(), "NOS Archive (*.NOS)"); 21 | 22 | if (fileName.isEmpty()) 23 | return; 24 | 25 | if (!fileName.endsWith(".NOS")) 26 | fileName += ".NOS"; 27 | 28 | QFile file(fileName); 29 | if (!file.open(QIODevice::WriteOnly)) 30 | { 31 | QMessageBox::critical(NULL, "Woops", "Couldn't open this file for writing"); 32 | return; 33 | } 34 | 35 | if (file.write(opener->encrypt(this)) == -1) 36 | { 37 | QMessageBox::critical(NULL, "Woops", "Couldn't write to this file"); 38 | return; 39 | } 40 | 41 | QMessageBox::information(NULL, "Yeah", "File exported into .NOS"); 42 | 43 | } 44 | 45 | int OnexTreeZlibItem::getId() 46 | { 47 | return id; 48 | } 49 | 50 | int OnexTreeZlibItem::getCreationDate() 51 | { 52 | return creationDate; 53 | } 54 | 55 | bool OnexTreeZlibItem::isCompressed() 56 | { 57 | return compressed; 58 | } 59 | 60 | OnexTreeZlibItem::~OnexTreeZlibItem() 61 | { 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Source/Ui/SingleImagePreview.cpp: -------------------------------------------------------------------------------- 1 | #include "SingleImagePreview.h" 2 | #include "ui_SingleImagePreview.h" 3 | 4 | SingleImagePreview::SingleImagePreview(QImage image, QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::SingleImagePreview) 7 | { 8 | ui->setupUi(this); 9 | ui->imgContent->setContextMenuPolicy(Qt::CustomContextMenu); 10 | connect(ui->imgContent, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showCustomMenu(QPoint))); 11 | 12 | ui->imgContent->setPixmap(QPixmap::fromImage(image)); 13 | 14 | } 15 | 16 | SingleImagePreview::~SingleImagePreview() 17 | { 18 | delete ui; 19 | } 20 | 21 | void SingleImagePreview::showCustomMenu(const QPoint &pos) 22 | { 23 | Q_UNUSED(pos); 24 | 25 | QMenu contextMenu(this); 26 | 27 | QAction exportAction("Export", this); 28 | connect(&exportAction, SIGNAL(triggered()), this, SLOT(exportImage())); 29 | contextMenu.addAction(&exportAction); 30 | 31 | contextMenu.exec(QCursor::pos()); 32 | } 33 | 34 | void SingleImagePreview::exportImage() 35 | { 36 | QString fileName = QFileDialog::getSaveFileName(0, tr("Save as..."), "", tr("PNG Image (*.png)")); 37 | 38 | if (fileName.isEmpty()) 39 | return; 40 | 41 | if (!fileName.endsWith(".png")) 42 | fileName += ".png"; 43 | 44 | if (ui->imgContent->pixmap()->toImage().save(fileName, "PNG", 100)) 45 | QMessageBox::information(NULL, "Yeah", "Image exported"); 46 | else 47 | QMessageBox::critical(NULL, "Woops", "Couldn't export that image"); 48 | 49 | } 50 | 51 | void SingleImagePreview::onReplaced(QImage newImage) 52 | { 53 | ui->imgContent->setPixmap(QPixmap::fromImage(newImage)); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Source/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Ui/SingleTextFilePreview.h" 10 | #include "Ui/FileInfo.h" 11 | #include "Openers/NosTextOpener.h" 12 | #include "Openers/NosZlibOpener.h" 13 | #include "Ui/SingleImagePreview.h" 14 | namespace Ui { 15 | class MainWindow; 16 | } 17 | 18 | class MainWindow : public QMainWindow 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit MainWindow(QWidget *parent = 0); 24 | ~MainWindow(); 25 | 26 | private slots: 27 | void onCustomMenuShow(const QPoint& point); 28 | void clearMenu(); 29 | void on_actionOpen_triggered(); 30 | 31 | void on_treeWidget_itemDoubleClicked(QTreeWidgetItem *treeItem, int column); 32 | 33 | void on_actionClose_selected_triggered(); 34 | 35 | void on_actionExit_triggered(); 36 | 37 | void on_actionClose_all_triggered(); 38 | 39 | void on_actionOptions_triggered(); 40 | 41 | void on_actionReplace_triggered(); 42 | 43 | void on_actionImport_triggered(); 44 | 45 | void on_actionExport_triggered(); 46 | 47 | void on_actionAbout_triggered(); 48 | 49 | void on_actionSave_as_triggered(); 50 | 51 | private: 52 | Ui::MainWindow *ui; 53 | NosTextOpener textOpener; 54 | NosZlibOpener zlibOpener; 55 | QMenu* contextMenu = nullptr; 56 | 57 | void openFile(QString path); 58 | void handleOpenResults(OnexTreeItem* item); 59 | bool hasValidHeader(QFile& file); 60 | 61 | virtual void dropEvent(QDropEvent *e) override; 62 | virtual void dragEnterEvent(QDragEnterEvent *e) override; 63 | }; 64 | 65 | #endif // MAINWINDOW_H 66 | -------------------------------------------------------------------------------- /Source/Decryptors/NosTextDatFileDecryptor.cpp: -------------------------------------------------------------------------------- 1 | #include "NosTextDatFileDecryptor.h" 2 | 3 | NosTextDatFileDecryptor::NosTextDatFileDecryptor() : 4 | cryptoArray({ 0x00, 0x20, 0x2D, 0x2E, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x0A, 0x00 }) 5 | { 6 | 7 | } 8 | 9 | QByteArray NosTextDatFileDecryptor::encrypt(QByteArray &array) 10 | { 11 | return QByteArray(); 12 | } 13 | 14 | QByteArray NosTextDatFileDecryptor::decrypt(QByteArray &array) 15 | { 16 | QByteArray decryptedFile; 17 | int currIndex = 0; 18 | while (currIndex < array.size()) 19 | { 20 | unsigned char currentByte = array.at(currIndex); 21 | currIndex++; 22 | if (currentByte == 0xFF) 23 | { 24 | decryptedFile.push_back(0xD); 25 | continue; 26 | } 27 | 28 | int validate = currentByte & 0x7F; 29 | 30 | if (currentByte & 0x80) 31 | { 32 | for (; validate > 0; validate -= 2) 33 | { 34 | if (currIndex >= array.size()) 35 | break; 36 | 37 | currentByte = array.at(currIndex); 38 | currIndex++; 39 | 40 | int firstByte = cryptoArray.at((currentByte & 0xF0) >> 4); 41 | decryptedFile.push_back(firstByte); 42 | 43 | if (validate <= 1) 44 | break; 45 | int secondByte = cryptoArray.at(currentByte & 0xF); 46 | 47 | if (!secondByte) 48 | break; 49 | 50 | decryptedFile.push_back(secondByte); 51 | } 52 | } 53 | else 54 | { 55 | for (; validate > 0; --validate) 56 | { 57 | if (currIndex >= array.size()) 58 | break; 59 | 60 | currentByte = array.at(currIndex); 61 | currIndex++; 62 | 63 | decryptedFile.push_back(currentByte ^ 0x33); 64 | } 65 | } 66 | } 67 | 68 | return decryptedFile; 69 | } 70 | 71 | NosTextDatFileDecryptor::~NosTextDatFileDecryptor() 72 | { 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Source/Ui/OnexNStpData.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexNStpData.h" 2 | 3 | OnexNStpData::OnexNStpData(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeImage(name, content, opener, id, creationDate, compressed) 5 | { 6 | 7 | } 8 | 9 | int OnexNStpData::getFormat() 10 | { 11 | return content.at(4); 12 | } 13 | 14 | QImage OnexNStpData::getImage() 15 | { 16 | ImageResolution resolution = this->getResolution(); 17 | 18 | int format = this->getFormat(); 19 | 20 | if (format == 0) 21 | return opener->getImageConverter().convertGBAR4444(content, resolution.x, resolution.y, 8); 22 | else if (format == 1) 23 | return opener->getImageConverter().convertARGB555(content, resolution.x, resolution.y, 8); 24 | else if (format == 2) 25 | return opener->getImageConverter().convertBGRA8888(content, resolution.x, resolution.y, 8); 26 | else 27 | { 28 | qDebug().noquote().nospace() << "Unknown format! (" << format << ")"; 29 | return QImage(resolution.x, resolution.y, QImage::Format_Invalid); 30 | } 31 | } 32 | 33 | ImageResolution OnexNStpData::getResolution() 34 | { 35 | int x = fromLittleEndianToShort(content.mid(0, 2)); 36 | int y = fromLittleEndianToShort(content.mid(2, 2)); 37 | 38 | return ImageResolution{x, y}; 39 | } 40 | 41 | void OnexNStpData::onReplace() 42 | { 43 | QImage image = importQImageFromSelectedUserFile(); 44 | if (image.isNull()) 45 | return; 46 | 47 | if (!hasGoodResolution(image.width(), image.height())) 48 | return; 49 | 50 | int format = this->getFormat(); 51 | 52 | if (format < 0 || format > 2) 53 | return; 54 | 55 | QByteArray newContent; 56 | newContent.push_back(content.mid(0, 8)); 57 | if (format == 0) 58 | newContent.push_back(opener->getImageConverter().toGBAR4444(image)); 59 | else if (format == 1) 60 | newContent.push_back(opener->getImageConverter().toARGB555(image)); 61 | else if (format == 2) 62 | newContent.push_back(opener->getImageConverter().toBGRA8888(image)); 63 | 64 | content = newContent; 65 | 66 | emit OnexTreeImage::replaceSignal(this->getImage()); 67 | } 68 | 69 | OnexNStpData::~OnexNStpData() 70 | { 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeImage.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexTreeImage.h" 2 | 3 | OnexTreeImage::OnexTreeImage(QString name, QByteArray content, NosZlibOpener *opener, int id, int creationDate, bool compressed) : 4 | OnexTreeZlibItem(name, content, opener, id, creationDate, compressed) 5 | { 6 | 7 | } 8 | 9 | bool OnexTreeImage::hasGoodResolution(int x, int y) 10 | { 11 | ImageResolution currentResolution = this->getResolution(); 12 | return (x == currentResolution.x && y == currentResolution.y); 13 | } 14 | 15 | QImage OnexTreeImage::importQImageFromSelectedUserFile() 16 | { 17 | QString fileName = getOpenDirectory("PNG Image (*.png)"); 18 | if (fileName.isEmpty()) 19 | return QImage(); 20 | 21 | QFile file(fileName); 22 | file.open(QIODevice::ReadOnly); 23 | QImage image = QImage::fromData(file.readAll()); 24 | file.close(); 25 | 26 | return image; 27 | } 28 | 29 | QWidget *OnexTreeImage::onClicked() 30 | { 31 | SingleImagePreview* imagePreview = new SingleImagePreview(this->getImage()); 32 | imagePreview->setWindowTitle(this->getName()); 33 | 34 | connect(this, SIGNAL(replaceSignal(QImage)), imagePreview, SLOT(onReplaced(QImage))); 35 | 36 | return imagePreview; 37 | } 38 | 39 | void OnexTreeImage::onExportAll() 40 | { 41 | QString directory = this->getSelectedDirectory(); 42 | if (directory.isEmpty()) 43 | return; 44 | 45 | int count = 0; 46 | for (int i = 0; i != this->childCount(); ++i) 47 | { 48 | OnexTreeImage* item = static_cast(this->child(i)); 49 | if (item->getImage().save(directory + item->getName() + ".png", "PNG", 100)) 50 | count++; 51 | } 52 | QString text = "Saved " + QString::number(count) + " of " + QString::number(this->childCount()) + " files."; 53 | QMessageBox msgBox(QMessageBox::Information, tr("End of operation"), text); 54 | msgBox.exec(); 55 | } 56 | 57 | void OnexTreeImage::onExportSingle() 58 | { 59 | QString fileName = getSaveDirectory(this->getName(), "PNG Image (*.png)"); 60 | 61 | if (fileName.isEmpty()) 62 | return; 63 | 64 | if (!fileName.endsWith(".png")) 65 | fileName += ".png"; 66 | 67 | if (this->getImage().save(fileName, "PNG", 100)) 68 | QMessageBox::information(NULL, "Yeah", "Image exported"); 69 | else 70 | QMessageBox::critical(NULL, "Woops", "Couldn't export that image"); 71 | } 72 | -------------------------------------------------------------------------------- /Source/Ui/FileInfo.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FileInfo 4 | 5 | 6 | 7 | 0 8 | 0 9 | 200 10 | 116 11 | 12 | 13 | 14 | 15 | 200 16 | 116 17 | 18 | 19 | 20 | 21 | 16777215 22 | 116 23 | 24 | 25 | 26 | Selected item info 27 | 28 | 29 | 30 | :/resources/oxe_icon_trans.ico:/resources/oxe_icon_trans.ico 31 | 32 | 33 | 1.000000000000000 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | 55 | 56 | Size (bytes) 57 | 58 | 59 | 60 | 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | Name 78 | 79 | 80 | 81 | 82 | 83 | 84 | Header 85 | 86 | 87 | 88 | 89 | 90 | 91 | Date 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /OnexExplorer.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2017-03-12T15:48:27 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = OnexExplorer 12 | TEMPLATE = app 13 | 14 | # The following define makes your compiler emit warnings if you use 15 | # any feature of Qt which as been marked as deprecated (the exact warnings 16 | # depend on your compiler). Please consult the documentation of the 17 | # deprecated API in order to know how to port your code away from it. 18 | DEFINES += QT_DEPRECATED_WARNINGS 19 | 20 | # You can also make your code fail to compile if you use deprecated APIs. 21 | # In order to do so, uncomment the following line. 22 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 23 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 24 | 25 | 26 | SOURCES += \ 27 | Source/main.cpp \ 28 | Source/Decryptors/NosTextDatFileDecryptor.cpp \ 29 | Source/Openers/NosTextOpener.cpp \ 30 | Source/MainWindow.cpp \ 31 | Source/Decryptors/NosTextOthersFileDecryptor.cpp \ 32 | Source/Openers/INosFileOpener.cpp \ 33 | Source/Ui/OnexTreeItem.cpp \ 34 | Source/Ui/SingleTextFilePreview.cpp \ 35 | Source/Decryptors/NosZlibDecryptor.cpp \ 36 | Source/Openers/NosZlibOpener.cpp \ 37 | Source/Ui/SingleImagePreview.cpp \ 38 | Source/ImageConverter.cpp \ 39 | Source/Ui/FileInfo.cpp \ 40 | Source/Ui/OnexTreeImage.cpp \ 41 | Source/Ui/OnexTreeText.cpp \ 42 | Source/Ui/OnexTreeZlibItem.cpp \ 43 | Source/Ui/OnexNSipData.cpp \ 44 | Source/Ui/OnexNS4BbData.cpp \ 45 | Source/Ui/OnexNStcData.cpp \ 46 | Source/Ui/OnexNStpData.cpp 47 | 48 | HEADERS += \ 49 | Source/Decryptors/NosTextDatFileDecryptor.h \ 50 | Source/Decryptors/INosDecryptor.h \ 51 | Source/Openers/INosFileOpener.h \ 52 | Source/Openers/NosTextOpener.h \ 53 | Source/MainWindow.h \ 54 | Source/Decryptors/NosTextOthersFileDecryptor.h \ 55 | Source/Ui/OnexTreeItem.h \ 56 | Source/Ui/OnexTreeItem.h \ 57 | Source/Ui/SingleTextFilePreview.h \ 58 | Source/Decryptors/NosZlibDecryptor.h \ 59 | Source/Openers/NosZlibOpener.h \ 60 | Source/NosEnumTypes.h \ 61 | Source/Ui/SingleImagePreview.h \ 62 | Source/ImageConverter.h \ 63 | Source/Ui/FileInfo.h \ 64 | Source/Ui/OnexTreeImage.h \ 65 | Source/Ui/OnexTreeText.h \ 66 | Source/Ui/OnexTreeZlibItem.h \ 67 | Source/Ui/OnexNSipData.h \ 68 | Source/Ui/OnexNS4BbData.h \ 69 | Source/Ui/OnexNStcData.h \ 70 | Source/Ui/OnexNStpData.h 71 | 72 | FORMS += \ 73 | Source/mainwindow.ui \ 74 | Source/Ui/SingleTextFilePreview.ui \ 75 | Source/Ui/SingleImagePreview.ui \ 76 | Source/Ui/FileInfo.ui 77 | 78 | DISTFILES += 79 | 80 | RESOURCES += \ 81 | resources.qrc 82 | 83 | RC_ICONS = ./resources/oxe_icon_trans.ico 84 | -------------------------------------------------------------------------------- /Source/Ui/OnexTreeItem.cpp: -------------------------------------------------------------------------------- 1 | #include "OnexTreeItem.h" 2 | 3 | OnexTreeItem::OnexTreeItem(QString name, QByteArray content) 4 | { 5 | this->name = name; 6 | this->content = content; 7 | this->setText(0, name); 8 | } 9 | 10 | QString OnexTreeItem::getSelectedDirectory() 11 | { 12 | QString dir = QFileDialog::getExistingDirectory(0, tr("Select Directory")); 13 | if (dir.isEmpty()) 14 | return dir; 15 | 16 | return dir + "/"; 17 | } 18 | 19 | QString OnexTreeItem::getSaveDirectory(QString name, QString filter) 20 | { 21 | return QFileDialog::getSaveFileName(0, tr("Save as..."), name, filter); 22 | } 23 | 24 | QString OnexTreeItem::getOpenDirectory(QString filter) 25 | { 26 | return QFileDialog::getOpenFileName(0, tr("Open..."), "", filter); 27 | } 28 | 29 | QByteArray OnexTreeItem::getContent() 30 | { 31 | return content; 32 | } 33 | 34 | bool OnexTreeItem::hasParent() 35 | { 36 | return QTreeWidgetItem::parent(); 37 | } 38 | 39 | short OnexTreeItem::fromLittleEndianToShort(QByteArray array) 40 | { 41 | return qFromLittleEndian(reinterpret_cast(array.data())); 42 | } 43 | 44 | int OnexTreeItem::getContentSize() 45 | { 46 | return content.size(); 47 | } 48 | 49 | QString OnexTreeItem::getName() 50 | { 51 | return name; 52 | } 53 | 54 | QMenu *OnexTreeItem::getContextMenu() 55 | { 56 | QMenu* contextMenu = new QMenu(); 57 | if (!hasParent()) 58 | { 59 | QAction* exportAllAction = new QAction(QObject::tr("Export all"), contextMenu); 60 | contextMenu->addAction(exportAllAction); 61 | QObject::connect(exportAllAction, SIGNAL(triggered(bool)), this, SLOT(onExportAll())); 62 | 63 | QAction* exportOriginalAction = new QAction(QObject::tr("Export as original"), contextMenu); 64 | contextMenu->addAction(exportOriginalAction); 65 | QObject::connect(exportOriginalAction, SIGNAL(triggered(bool)), this, SLOT(onExporAsOriginal())); 66 | 67 | QAction* closeThisItem = new QAction(QObject::tr("Close"), contextMenu); 68 | contextMenu->addAction(closeThisItem); 69 | QObject::connect(closeThisItem, SIGNAL(triggered(bool)), this, SLOT(actionClose())); 70 | 71 | } 72 | else 73 | { 74 | QAction* exportSingleAction = new QAction(QObject::tr("Export"), contextMenu); 75 | contextMenu->addAction(exportSingleAction); 76 | QObject::connect(exportSingleAction, SIGNAL(triggered(bool)), this, SLOT(onExportSingle())); 77 | 78 | QAction* exportSingleToRawAction = new QAction(QObject::tr("Export to raw"), contextMenu); 79 | contextMenu->addAction(exportSingleToRawAction); 80 | QObject::connect(exportSingleToRawAction, SIGNAL(triggered(bool)), this, SLOT(onExporSingleRaw())); 81 | 82 | QAction* replaceAction = new QAction(QObject::tr("Replace"), contextMenu); 83 | contextMenu->addAction(replaceAction); 84 | QObject::connect(replaceAction, SIGNAL(triggered(bool)), this, SLOT(onReplace())); 85 | } 86 | 87 | return contextMenu; 88 | } 89 | 90 | OnexTreeItem::~OnexTreeItem() 91 | { 92 | 93 | } 94 | 95 | void OnexTreeItem::onExportAll() 96 | { 97 | QMessageBox::warning(NULL, tr("Not yet"), tr("This isn't implemented yet")); 98 | } 99 | 100 | void OnexTreeItem::onExportSingle() 101 | { 102 | QMessageBox::warning(NULL, tr("Not yet"), tr("This isn't implemented yet")); 103 | } 104 | 105 | void OnexTreeItem::onExporSingleRaw() 106 | { 107 | QString fileName = getSaveDirectory(this->getName(), "Raw data (*.rawdata)"); 108 | if (fileName.isEmpty()) 109 | return; 110 | 111 | if (!fileName.endsWith(tr(".rawdata"))) 112 | fileName += ".rawdata"; 113 | 114 | QFile file(fileName); 115 | file.open(QIODevice::WriteOnly); 116 | if (file.write(this->getContent()) == -1) 117 | QMessageBox::critical(NULL, tr("Woops"), tr("Couldn't save that file")); 118 | else 119 | QMessageBox::information(NULL, tr("Yeah"), tr("File exported")); 120 | file.close(); 121 | } 122 | 123 | void OnexTreeItem::onExporAsOriginal() 124 | { 125 | QMessageBox::warning(NULL, tr("Not yet"), tr("This isn't implemented yet")); 126 | } 127 | 128 | void OnexTreeItem::onReplace() 129 | { 130 | QMessageBox::warning(NULL, tr("Not yet"), tr("This isn't implemented yet")); 131 | } 132 | 133 | void OnexTreeItem::actionClose() 134 | { 135 | QList selectedItems = this->treeWidget()->selectedItems(); 136 | 137 | foreach (auto& item, selectedItems) 138 | delete item; 139 | } 140 | -------------------------------------------------------------------------------- /Source/Openers/NosZlibOpener.cpp: -------------------------------------------------------------------------------- 1 | #include "NosZlibOpener.h" 2 | #include "../Ui/OnexTreeZlibItem.h" 3 | #include "../Ui/OnexNSipData.h" 4 | #include "../Ui/OnexNS4BbData.h" 5 | #include "../Ui/OnexNStcData.h" 6 | #include "../Ui/OnexNStpData.h" 7 | 8 | 9 | QByteArray NosZlibOpener::toBigEndian(qint32 value) 10 | { 11 | QByteArray result; 12 | result.resize(4); 13 | 14 | qToBigEndian(value, reinterpret_cast(result.data())); 15 | 16 | return result; 17 | } 18 | 19 | int NosZlibOpener::getNTHeaderNumber(QByteArray &array) 20 | { 21 | if (array.mid(0, 7) == "NT Data") 22 | return array.mid(8, 2).toInt(); 23 | else if (array.mid(0, 10) == "32GBS V1.0") 24 | return 101; 25 | else if (array.mid(0, 11) == "CCINF V1.20") 26 | return 102; 27 | else if (array.mid(0, 10) == "ITEMS V1.0") 28 | return 103; 29 | else 30 | return 199; 31 | } 32 | 33 | OnexTreeItem *NosZlibOpener::createItemFromHeader(int header, QString name, QByteArray& array, int fileId, int creationDate, bool compressed) 34 | { 35 | switch (header) 36 | { 37 | case NSipData: 38 | return new OnexNSipData(name, array, this, fileId, creationDate, compressed); 39 | break; 40 | 41 | case NS4BbData: 42 | return new OnexNS4BbData(name, array, this, fileId, creationDate, compressed); 43 | break; 44 | 45 | case NStcData: 46 | return new OnexNStcData(name, array, this, fileId, creationDate, compressed); 47 | break; 48 | 49 | case NStpData: 50 | return new OnexNStpData(name, array, this, fileId, creationDate, compressed); 51 | break; 52 | 53 | case NStpeData: 54 | return new OnexNStpData(name, array, this, fileId, creationDate, compressed); 55 | break; 56 | 57 | case NStpuData: 58 | return new OnexNStpData(name, array, this, fileId, creationDate, compressed); 59 | break; 60 | 61 | default: 62 | return new OnexTreeZlibItem(name, array, this, fileId, creationDate, compressed); 63 | break; 64 | } 65 | } 66 | 67 | NosZlibOpener::NosZlibOpener() 68 | { 69 | 70 | } 71 | 72 | ImageConverter &NosZlibOpener::getImageConverter() 73 | { 74 | return imageConverter; 75 | } 76 | 77 | OnexTreeItem *NosZlibOpener::decrypt(QFile &file) 78 | { 79 | 80 | file.seek(0); 81 | 82 | QByteArray header = file.read(NOS_HEADER_SIZE); 83 | 84 | int ntHeaderNumber = getNTHeaderNumber(header); 85 | int fileAmount = readNextInt(file); 86 | 87 | OnexTreeItem *item = createItemFromHeader(ntHeaderNumber, neatFileName(file.fileName()), header); 88 | 89 | QByteArray separatorByte = file.read(1); 90 | 91 | for (int i = 0; i != fileAmount; ++i) 92 | { 93 | int id = readNextInt(file); 94 | int offset = readNextInt(file); 95 | 96 | int previousOffset = file.pos(); 97 | 98 | file.seek(offset); 99 | 100 | int creationDate = readNextInt(file); 101 | int dataSize = readNextInt(file); 102 | int compressedDataSize = readNextInt(file); 103 | bool isCompressed = file.read(1).at(0); 104 | QByteArray data = file.read(compressedDataSize); 105 | if (isCompressed) 106 | { 107 | QByteArray bigEndian = toBigEndian(dataSize); 108 | data.push_front(bigEndian); 109 | data = decryptor.decrypt(data); 110 | } 111 | 112 | item->addChild(createItemFromHeader(ntHeaderNumber, QString::number(id), data, id, creationDate, isCompressed)); 113 | file.seek(previousOffset); 114 | 115 | } 116 | 117 | //encrypt(item); 118 | 119 | return item; 120 | } 121 | 122 | QByteArray NosZlibOpener::encrypt(OnexTreeItem *item) 123 | { 124 | if (item->hasParent()) 125 | return QByteArray(); 126 | 127 | QByteArray fileHeader = item->getContent(); 128 | fileHeader.push_back(writeNextInt(item->childCount())); 129 | fileHeader.push_back((char)0x0);//separator byte 130 | 131 | QByteArray offsetArray; 132 | int sizeOfOffsetArray = item->childCount() * 8; 133 | 134 | QByteArray contentArray; 135 | 136 | int firstFileOffset = fileHeader.size() + sizeOfOffsetArray; 137 | 138 | for(int i = 0; i != item->childCount(); ++i) 139 | { 140 | int currentFileOffset = firstFileOffset + contentArray.size(); 141 | OnexTreeZlibItem* currentItem = static_cast(item->child(i)); 142 | contentArray.push_back(writeNextInt(currentItem->getCreationDate())); 143 | QByteArray content = currentItem->getContent(); 144 | contentArray.push_back(writeNextInt(content.size())); 145 | 146 | if (currentItem->isCompressed()) 147 | content = decryptor.encrypt(content); 148 | 149 | int compressedContentSize = content.size(); 150 | if (currentItem->isCompressed()) 151 | compressedContentSize -= 4; //qCompress add the size at the front of array 152 | 153 | 154 | contentArray.push_back(writeNextInt(compressedContentSize)); 155 | contentArray.push_back(currentItem->isCompressed()); 156 | 157 | if (currentItem->isCompressed()) 158 | contentArray.push_back(content.mid(4)); 159 | else 160 | contentArray.push_back(content); 161 | 162 | offsetArray.push_back(writeNextInt(currentItem->getId())); 163 | offsetArray.push_back(writeNextInt(currentFileOffset)); 164 | 165 | } 166 | 167 | QByteArray result; 168 | result.push_back(fileHeader); 169 | result.push_back(offsetArray); 170 | result.push_back(contentArray); 171 | 172 | 173 | return result; 174 | } 175 | -------------------------------------------------------------------------------- /Source/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | 15 | 500 16 | 300 17 | 18 | 19 | 20 | false 21 | 22 | 23 | OnexExplorer [Beta] 24 | 25 | 26 | 27 | :/resources/oxe_icon_trans.ico 28 | :/resources/oxe_icon_trans.ico:/resources/oxe_icon_trans.ico 29 | 30 | 31 | 32 | 33 | 34 | 35 | QFrame::StyledPanel 36 | 37 | 38 | QFrame::Plain 39 | 40 | 41 | 1 42 | 43 | 44 | 0 45 | 46 | 47 | 48 | 49 | 255 50 | 255 51 | 255 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 0 62 | 0 63 | 64 | 65 | 66 | 67 | 171 68 | 16777215 69 | 70 | 71 | 72 | false 73 | 74 | 75 | 76 | 1 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 0 87 | 0 88 | 800 89 | 20 90 | 91 | 92 | 93 | 94 | File 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | false 107 | 108 | 109 | ? 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | Tools 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | Open 132 | 133 | 134 | Ctrl+O 135 | 136 | 137 | 138 | 139 | true 140 | 141 | 142 | Save as... 143 | 144 | 145 | Ctrl+S 146 | 147 | 148 | 149 | 150 | Close selected 151 | 152 | 153 | Ctrl+W 154 | 155 | 156 | 157 | 158 | true 159 | 160 | 161 | Export 162 | 163 | 164 | Ctrl+E 165 | 166 | 167 | 168 | 169 | true 170 | 171 | 172 | Import 173 | 174 | 175 | Ctrl+I 176 | 177 | 178 | 179 | 180 | false 181 | 182 | 183 | Help 184 | 185 | 186 | 187 | 188 | Exit 189 | 190 | 191 | Ctrl+Q 192 | 193 | 194 | 195 | 196 | false 197 | 198 | 199 | Options 200 | 201 | 202 | Ctrl+, 203 | 204 | 205 | 206 | 207 | true 208 | 209 | 210 | Close all 211 | 212 | 213 | Ctrl+Shift+W 214 | 215 | 216 | 217 | 218 | Replace 219 | 220 | 221 | Ctrl+R 222 | 223 | 224 | 225 | 226 | About 227 | 228 | 229 | 230 | 231 | 232 | treeWidget 233 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Source/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | MainWindow::MainWindow(QWidget *parent) : 5 | QMainWindow(parent), 6 | ui(new Ui::MainWindow) 7 | { 8 | ui->setupUi(this); 9 | this->setAcceptDrops(true); 10 | 11 | ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); 12 | 13 | connect(ui->treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onCustomMenuShow(QPoint))); 14 | } 15 | 16 | MainWindow::~MainWindow() 17 | { 18 | if (contextMenu) 19 | { 20 | clearMenu(); 21 | delete contextMenu; 22 | } 23 | 24 | delete ui; 25 | } 26 | 27 | void MainWindow::onCustomMenuShow(const QPoint &point) 28 | { 29 | Q_UNUSED(point); 30 | 31 | if (contextMenu) 32 | { 33 | clearMenu(); 34 | delete contextMenu; 35 | contextMenu = nullptr; 36 | } 37 | OnexTreeItem* item = static_cast(ui->treeWidget->currentItem()); 38 | if (item == nullptr) 39 | return; 40 | 41 | contextMenu = item->getContextMenu(); 42 | 43 | if (contextMenu->isEmpty()) 44 | return; 45 | qDebug() << contextMenu->height(); 46 | contextMenu->exec(QCursor::pos()); 47 | } 48 | 49 | void MainWindow::clearMenu() 50 | { 51 | qDebug() << "Disposing menu"; 52 | QList actions = contextMenu->actions(); 53 | 54 | for (auto& action : actions) 55 | delete action; 56 | 57 | contextMenu->clear(); 58 | } 59 | 60 | void MainWindow::on_actionOpen_triggered() 61 | { 62 | QFileDialog openDialog(this); 63 | 64 | openDialog.setFileMode(QFileDialog::ExistingFiles); 65 | openDialog.setNameFilter(tr("NosTale Files (*.NOS)")); 66 | openDialog.setViewMode(QFileDialog::Detail); 67 | 68 | QStringList selectedFiles; 69 | if (openDialog.exec()) 70 | selectedFiles = openDialog.selectedFiles(); 71 | 72 | if (!selectedFiles.empty()) 73 | { 74 | for (auto& file : selectedFiles) 75 | openFile(file); 76 | } 77 | } 78 | 79 | void MainWindow::openFile(QString path) 80 | { 81 | QFile file(path); 82 | 83 | if (!file.open(QIODevice::ReadOnly)) 84 | return; 85 | 86 | if (hasValidHeader(file)) 87 | handleOpenResults(zlibOpener.decrypt(file)); 88 | else 89 | handleOpenResults(textOpener.decrypt(file)); 90 | 91 | file.close(); 92 | } 93 | 94 | void MainWindow::handleOpenResults(OnexTreeItem *item) 95 | { 96 | ui->treeWidget->addTopLevelItem(item); 97 | item->setExpanded(true); 98 | } 99 | 100 | bool MainWindow::hasValidHeader(QFile &file) 101 | { 102 | file.seek(0); 103 | QByteArray header = file.read(0x0B); 104 | if (header.mid(0, 7) == "NT Data" || header.mid(0, 10) == "32GBS V1.0" || header.mid(0, 10) == "ITEMS V1.0") 105 | return true; 106 | return false; 107 | } 108 | 109 | void MainWindow::dropEvent(QDropEvent *e) 110 | { 111 | for (auto& url : e->mimeData()->urls()) 112 | { 113 | QString fileName = url.toLocalFile(); 114 | openFile(fileName); 115 | } 116 | } 117 | 118 | void MainWindow::dragEnterEvent(QDragEnterEvent *e) 119 | { 120 | for (auto& url : e->mimeData()->urls()) 121 | { 122 | QString fileName = url.toLocalFile(); 123 | if (QFileInfo(fileName).suffix() != "NOS") 124 | return; 125 | } 126 | e->acceptProposedAction(); 127 | } 128 | 129 | void MainWindow::on_treeWidget_itemDoubleClicked(QTreeWidgetItem *treeItem, int column) 130 | { 131 | Q_UNUSED(column); 132 | 133 | OnexTreeItem* item = static_cast(treeItem); 134 | 135 | if (item->childCount() != 0) 136 | return; 137 | 138 | if (!item->hasParent()) 139 | return; 140 | 141 | QWidget* previewWindow = item->onClicked(); 142 | 143 | 144 | if (!previewWindow) 145 | { 146 | QMessageBox::warning(this, "Not supported", "This NosTale file cannot be opened yet."); 147 | return; 148 | } 149 | 150 | ui->mdiArea->addSubWindow(previewWindow); 151 | previewWindow->setAttribute(Qt::WA_DeleteOnClose); 152 | previewWindow->show(); 153 | } 154 | 155 | void MainWindow::on_actionClose_selected_triggered() 156 | { 157 | QList selectedItems = ui->treeWidget->selectedItems(); 158 | foreach (auto& item, selectedItems) 159 | delete item; 160 | } 161 | 162 | void MainWindow::on_actionReplace_triggered() 163 | { 164 | if(ui->treeWidget->currentItem()){ 165 | 166 | OnexTreeItem* item = static_cast(ui->treeWidget->currentItem()); 167 | if(item->hasParent()){ 168 | 169 | item->onReplace(); 170 | }else{ 171 | QMessageBox::information(NULL, tr("Info"), tr("Select correct file not *.NOS")); 172 | } 173 | }else{ 174 | QMessageBox::information(NULL, tr("Info"), tr("Select file first")); 175 | } 176 | } 177 | void MainWindow::on_actionExport_triggered() 178 | { 179 | if(ui->treeWidget->currentItem()){ 180 | 181 | OnexTreeItem* item = static_cast(ui->treeWidget->currentItem()); 182 | if(item->hasParent()){ 183 | 184 | item->onExportSingle(); 185 | }else{ 186 | QMessageBox::information(NULL, tr("Info"), tr("Select correct file not *.NOS")); 187 | } 188 | }else{ 189 | QMessageBox::information(NULL, tr("Info"), tr("Select file first")); 190 | } 191 | } 192 | void MainWindow::on_actionImport_triggered() 193 | { 194 | QMessageBox::warning(NULL, tr("Not yet"), tr("This isn't implemented yet")); 195 | } 196 | 197 | void MainWindow::on_actionAbout_triggered() 198 | { 199 | QMessageBox::information(NULL, tr("About Project"), tr("OnexExplorer is an open-source tool for unpacking and repacking .NOS data files from game called NosTale. " 200 | "
It can open almost all .NOS files and show the data stored in them." 201 | "
GitHub: https://github.com/OnexTale/OnexExplorer")); 202 | } 203 | 204 | void MainWindow::on_actionSave_as_triggered() 205 | { 206 | if(ui->treeWidget->currentItem()){ 207 | 208 | OnexTreeItem* item = static_cast(ui->treeWidget->currentItem()); 209 | if(!item->hasParent()){ 210 | item->onExporAsOriginal(); 211 | }else{ 212 | QMessageBox::information(NULL, tr("Info"), tr("Select correct *.NOS file")); 213 | } 214 | }else{ 215 | QMessageBox::information(NULL, tr("Info"), tr("Select .NOS file first")); 216 | } 217 | } 218 | 219 | void MainWindow::on_actionExit_triggered() 220 | { 221 | QMessageBox::StandardButton message = QMessageBox::question(this, "", 222 | "Exit program?", 223 | QMessageBox::Yes | QMessageBox::No, 224 | QMessageBox::No); 225 | if (message == QMessageBox::Yes) 226 | QApplication::quit(); 227 | } 228 | 229 | void MainWindow::on_actionClose_all_triggered() 230 | { 231 | QMessageBox::StandardButton message = QMessageBox::question(this, "", 232 | "Close all items?", 233 | QMessageBox::Yes | QMessageBox::No, 234 | QMessageBox::No); 235 | 236 | if (message == QMessageBox::Yes) 237 | { 238 | ui->treeWidget->clear(); 239 | } 240 | } 241 | 242 | void MainWindow::on_actionOptions_triggered() 243 | { 244 | OnexTreeItem* item = static_cast(ui->treeWidget->currentItem()); 245 | if (item == nullptr) 246 | return; 247 | if (item->childCount() != 0) 248 | return; 249 | FileInfo dialog(item); 250 | dialog.exec(); 251 | } 252 | -------------------------------------------------------------------------------- /Source/ImageConverter.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageConverter.h" 2 | #include 3 | 4 | QImage ImageConverter::convertGBAR4444(QByteArray &array, int width, int height, int startByte) 5 | ///GBAR = ARGB (endianness) 6 | { 7 | qDebug() << "Opened GBAR4444 image."; 8 | QImage img(width, height, QImage::Format_ARGB32); 9 | 10 | img.fill(Qt::transparent); 11 | 12 | for (int y = 0; y < height; ++y) 13 | { 14 | for (int x = 0; x < width; ++x) 15 | { 16 | uchar gb = array.at(startByte + y * 2 * height + x * 2); 17 | uchar ar = array.at(startByte + y * 2 * height + x * 2 + 1); 18 | 19 | uchar g = gb >> 4; 20 | uchar b = gb & 0xF; 21 | uchar a = ar >> 4; 22 | uchar r = ar & 0xF; 23 | 24 | img.setPixel(x, y, qRgba(r * 0x11, g * 0x11, b * 0x11, a * 0x11)); 25 | } 26 | } 27 | 28 | return img; 29 | } 30 | 31 | QImage ImageConverter::convertBGRA8888(QByteArray &array, int width, int height, int startByte) 32 | { 33 | qDebug() << "Opened BGRA8888 image."; 34 | QImage img(width, height, QImage::Format_ARGB32); 35 | 36 | img.fill(Qt::transparent); 37 | 38 | for (int y = 0; y < height; ++y) 39 | { 40 | for (int x = 0; x < width; ++x) 41 | { 42 | uchar b = array.at(startByte + y * 4 * height + x * 4); 43 | uchar g = array.at(startByte + y * 4 * height + x * 4 + 1); 44 | uchar r = array.at(startByte + y * 4 * height + x * 4 + 2); 45 | uchar a = array.at(startByte + y * 4 * height + x * 4 + 3); 46 | 47 | img.setPixel(x, y, qRgba(r, g, b, a)); 48 | } 49 | } 50 | 51 | return img; 52 | } 53 | 54 | QImage ImageConverter::convertARGB555(QByteArray& array, int width, int height, int startByte) 55 | { 56 | qDebug() << "Opened ARGB555 image."; 57 | QImage img(width, height, QImage::Format_ARGB32); 58 | 59 | img.fill(Qt::transparent); 60 | 61 | for (int y = 0; y < height; ++y) 62 | { 63 | for (int x = 0; x < width; ++x) 64 | { 65 | ushort bytes = qFromLittleEndian(reinterpret_cast(array.mid(startByte + y * 2 * height + x * 2, 2).data())); 66 | 67 | uchar a = 255*(bytes & 0x8000) >> 15; // 0x8000 = 0b1000000000000000 68 | uchar r = 8*(bytes & 0x7C00) >> 10; // 0x7C00 = 0b0111110000000000 69 | uchar g = 8*(bytes & 0x3E0) >> 5; //0x3E0 = 0b0000001111100000 70 | uchar b = 8*(bytes & 0x1F); // 0x1F = 0b0000000000011111 71 | 72 | img.setPixel(x, y, qRgba(r, g, b, a)); 73 | } 74 | } 75 | 76 | return img; 77 | } 78 | 79 | QImage ImageConverter::convertNSTC(QByteArray &array, int width, int height, int startByte) 80 | { 81 | qDebug() << "Opened NSTC image."; 82 | QImage img(width, height, QImage::Format_ARGB32); 83 | img.fill(Qt::transparent); 84 | 85 | for (int x = 0; x < width; ++x) 86 | { 87 | for (int y = 0; y < height; ++y) 88 | { 89 | uchar value = array.at(startByte + y * width + x); 90 | if (colors.contains(value)) 91 | img.setPixel(x, y, colors[value].rgb()); 92 | else 93 | img.setPixel(x, y, colors[0xFF].rgb()); 94 | } 95 | } 96 | 97 | return img.scaled(QSize(width*2, height*2)); 98 | } 99 | 100 | QImage ImageConverter::convertBGRA8888_INTERLACED(QByteArray &array, int width, int height, int startByte) 101 | { 102 | qDebug() << "Opened BGRA888_INTERLACED image."; 103 | QImage img(width, height, QImage::Format_RGBA8888); 104 | img.fill(Qt::transparent); 105 | 106 | short num = 0, x = 0, y = 0; 107 | for (int i = 0; i < array.size() - startByte;) 108 | { 109 | uchar b = array.at(startByte + i++); 110 | uchar g = array.at(startByte + i++); 111 | uchar r = array.at(startByte + i++); 112 | uchar a = array.at(startByte + i++); 113 | img.setPixel(x, y, qRgba(r, g, b, a)); 114 | 115 | x++; 116 | if (x == (num + 256) || x == width) 117 | { 118 | x = num; 119 | y++; 120 | } 121 | if (y == height) 122 | { 123 | y = 0; 124 | num += 256; 125 | x = num; 126 | } 127 | } 128 | return img; 129 | } 130 | 131 | QImage ImageConverter::convertBARG4444(QByteArray &array, int width, int height, int startByte) 132 | ///BARG = RGBA (endianness) 133 | { 134 | qDebug() << "Opened BARG4444 image."; 135 | QImage img(width, height, QImage::Format_ARGB32); 136 | 137 | img.fill(Qt::transparent); 138 | 139 | for (int y = 0; y < height; ++y) 140 | { 141 | for (int x = 0; x < width; ++x) 142 | { 143 | uchar ba = array.at(startByte + y * 2 * height + x * 2); 144 | uchar rg = array.at(startByte + y * 2 * height + x * 2 + 1); 145 | 146 | uchar b = ba >> 4; 147 | uchar a = ba & 0xF; 148 | uchar r = rg >> 4; 149 | uchar g = rg & 0xF; 150 | 151 | img.setPixel(x, y, qRgba(r * 0x11, g * 0x11, b * 0x11, a * 0x11)); 152 | } 153 | } 154 | 155 | return img; 156 | } 157 | // //////////////////////////////////////////////////////////////////////////////////////////////////////// 158 | QByteArray ImageConverter::toGBAR4444(QImage &image) 159 | { 160 | qDebug() << "Replaced GBAR4444 image."; 161 | QByteArray data; 162 | 163 | for (int y = 0; y < image.height(); ++y) 164 | { 165 | for (int x = 0; x < image.width(); ++x) 166 | { 167 | QRgb currentPixel = image.pixel(x, y); 168 | 169 | uchar green = qGreen(currentPixel) / 0x11; 170 | uchar blue = qBlue(currentPixel) / 0x11; 171 | uchar alpha = qAlpha(currentPixel) / 0x11; 172 | uchar red = qRed(currentPixel) / 0x11; 173 | 174 | uchar gb = (green << 4) + blue; 175 | uchar ar = (alpha << 4) + red; 176 | 177 | data.push_back(gb); 178 | data.push_back(ar); 179 | } 180 | } 181 | 182 | return data; 183 | } 184 | 185 | QByteArray ImageConverter::toNSTC(QImage &image) 186 | { 187 | qDebug() << "Replaced NSTC image."; 188 | QByteArray data; 189 | int i = 0, j = 0; 190 | 191 | for (int y = 0; y < image.height(); ++y) 192 | { 193 | for (int x = 0; x < image.width(); ++x) 194 | { 195 | QRgb currentPixel = image.pixel(x, y); 196 | QColor pixColor = qRgb(qRed(currentPixel), qGreen(currentPixel), qBlue(currentPixel)); 197 | if (colors.values().contains(pixColor)) 198 | { 199 | i++; 200 | data.push_back(colors.key(pixColor)); 201 | } 202 | else 203 | { 204 | j++; 205 | data.push_back(0xFF); 206 | } 207 | } 208 | } 209 | return data; 210 | } 211 | 212 | QByteArray ImageConverter::toBGRA8888(QImage &image) 213 | { 214 | qDebug() << "Replaced BGRA8888 image."; 215 | QByteArray data; 216 | 217 | for (int y = 0; y < image.height(); ++y) 218 | { 219 | for (int x = 0; x < image.width(); ++x) 220 | { 221 | QRgb currentPixel = image.pixel(x, y); 222 | uchar alpha = qAlpha(currentPixel); 223 | uchar red = qRed(currentPixel); 224 | uchar green = qGreen(currentPixel); 225 | uchar blue = qBlue(currentPixel); 226 | 227 | data.push_back(blue); 228 | data.push_back(green); 229 | data.push_back(red); 230 | data.push_back(alpha); 231 | } 232 | } 233 | 234 | return data; 235 | } 236 | 237 | QByteArray ImageConverter::toARGB555(QImage &image) 238 | { 239 | qDebug() << "Replaced ARGB555 image."; 240 | //NOPE 241 | QByteArray data; 242 | 243 | for (int y = 0; y < image.height(); ++y) 244 | { 245 | for (int x = 0; x < image.width(); ++x) 246 | { 247 | QRgb currentPixel = image.pixel(x, y); 248 | 249 | uchar alpha = qAlpha(currentPixel) / 0xFF; //full alpha or gtfo 250 | uchar red = qRed(currentPixel) / 0x08; 251 | uchar green = qGreen(currentPixel) / 0x08; 252 | uchar blue = qBlue(currentPixel) / 0x08; 253 | 254 | ushort bytes = (alpha << 15) | (red << 10) | (green << 5) | (blue); 255 | 256 | uchar first = bytes >> 8; 257 | uchar second = bytes & 0xFF; 258 | data.push_back(second); 259 | data.push_back(first); 260 | } 261 | } 262 | 263 | return data; 264 | } 265 | 266 | QByteArray ImageConverter::toBGRA8888_INTERLACED(QImage &image) 267 | { 268 | qDebug() << "Replaced BGRA8888_INTERLACED image."; 269 | QByteArray data; 270 | 271 | short num = 0, x = 0, y = 0; 272 | for (int i = 0; i < image.width()*image.height(); i++) 273 | { 274 | QRgb currentPixel = image.pixel(x, y); 275 | uchar b = qBlue(currentPixel); 276 | uchar g = qGreen(currentPixel); 277 | uchar r = qRed(currentPixel); 278 | uchar a = qAlpha(currentPixel); 279 | data.push_back(b); 280 | data.push_back(g); 281 | data.push_back(r); 282 | data.push_back(a); 283 | 284 | x++; 285 | if (x == (num + 256) || x == image.width()) 286 | { 287 | x = num; 288 | y++; 289 | } 290 | if (y == image.height()) 291 | { 292 | y = 0; 293 | num += 256; 294 | x = num; 295 | } 296 | } 297 | 298 | return data; 299 | } 300 | 301 | QByteArray ImageConverter::toBARG4444(QImage &image) 302 | { 303 | qDebug() << "Replaced BARG4444 image."; 304 | //only in 2k6 NSip, not tested, should work tho as its the same as GBAR4444 but different order. 305 | QByteArray data; 306 | 307 | for (int y = 0; y < image.height(); ++y) 308 | { 309 | for (int x = 0; x < image.width(); ++x) 310 | { 311 | QRgb currentPixel = image.pixel(x, y); 312 | 313 | uchar blue = qBlue(currentPixel) / 0x11; 314 | uchar alpha = qAlpha(currentPixel) / 0x11; 315 | uchar red = qRed(currentPixel) / 0x11; 316 | uchar green = qGreen(currentPixel) / 0x11; 317 | 318 | uchar ba = (blue << 4) + alpha; 319 | uchar rg = (red << 4) + green; 320 | 321 | data.push_back(ba); 322 | data.push_back(rg); 323 | } 324 | } 325 | 326 | return data; 327 | } 328 | 329 | ImageConverter::ImageConverter() 330 | { 331 | colors[0x0] = qRgb(255, 255, 255); 332 | colors[0x1] = qRgb(100, 100, 100); 333 | colors[0x2] = qRgb(100, 150, 100); 334 | colors[0x3] = qRgb(0, 0, 0); 335 | colors[0x9] = qRgb(100, 100, 150); 336 | colors[0x0a] = qRgb(0, 50, 200); 337 | colors[0x0b] = qRgb(150, 100, 100); 338 | colors[0x0d] = qRgb(150, 150, 100); 339 | colors[0x10] = qRgb(150, 100, 150); 340 | colors[0x11] = qRgb(0, 200, 50); 341 | colors[0x12] = qRgb(200, 50, 0); 342 | colors[0x13] = qRgb(250, 230, 10); 343 | colors[0xFF] = qRgb(150, 0, 255); 344 | } 345 | 346 | --------------------------------------------------------------------------------