From e6b5d9656ac08975a1221113958db1120233408c Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Fri, 27 Sep 2019 09:01:25 -0500 Subject: [PATCH 01/12] Update BUILD.md the `git clone` command provided doesn't work and gives this error on Debian ``` $ git clone --recursive git@github.com:MultiMC/MultiMC5.git src Cloning into 'src'... The authenticity of host 'github.com (192.30.253.113)' can't be established. RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'github.com,192.30.253.113' (RSA) to the list of known hosts. git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. ``` I am suggesting an alternative command to provide to users in BUILD.md instead. --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index d347ba14..19a929a7 100644 --- a/BUILD.md +++ b/BUILD.md @@ -50,7 +50,7 @@ mkdir ~/MultiMC && cd ~/MultiMC mkdir build mkdir install # clone the complete source -git clone --recursive git@github.com:MultiMC/MultiMC5.git src +git clone --recursive https://github.com/MultiMC/MultiMC5.git src # configure the project cd build cmake -DCMAKE_INSTALL_PREFIX=../install ../src From bc04d89c32142094eec161709cf3932b7213b058 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Wed, 5 Feb 2020 00:29:23 +0100 Subject: [PATCH 02/12] feat: add --import command-line option When specified, opens the "Import from zip" dialog as soon as the main window is shown, with the URL field prefilled with the argument given to the option. Closes #2998 --- application/MainWindow.h | 4 ++-- application/MultiMC.cpp | 12 ++++++++++++ application/MultiMC.h | 2 ++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/application/MainWindow.h b/application/MainWindow.h index a415b5e8..00b8e043 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -57,6 +57,8 @@ public: void checkInstancePathForProblems(); void updatesAllowedChanged(bool allowed); + + void droppedURLs(QList urls); signals: void isClosing(); @@ -180,8 +182,6 @@ private slots: */ void downloadUpdates(GoUpdate::Status status); - void droppedURLs(QList urls); - void konamiTriggered(); void globalSettingsClosed(); diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index c4e4392d..039fb11d 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,10 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) parser.addSwitch("alive"); parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after MultiMC starts"); + parser.addOption("import"); + parser.addShortOpt("import", 'I'); + parser.addDocumentation("import", "Import instance from specified zip (local path or URL)"); + // parse the arguments try { @@ -207,6 +212,7 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) } m_instanceIdToLaunch = args["launch"].toString(); m_liveCheck = args["alive"].toBool(); + m_zipToImport = args["import"].toUrl(); QString origcwdPath = QDir::currentPath(); QString binPath = applicationDirPath(); @@ -812,6 +818,12 @@ void MultiMC::performMainStartupAction() showMainWindow(false); qDebug() << "<> Main window shown."; } + + if (!m_zipToImport.isEmpty()) { + qDebug() << "<> Importing instance from zip:" << m_zipToImport.toString(); + QList urls = { m_zipToImport }; + m_mainWindow->droppedURLs(urls); + } } void MultiMC::showFatalErrorMessage(const QString& title, const QString& content) diff --git a/application/MultiMC.h b/application/MultiMC.h index d7c727e0..e6588a14 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -221,5 +222,6 @@ private: public: QString m_instanceIdToLaunch; bool m_liveCheck = false; + QUrl m_zipToImport; std::unique_ptr logFile; }; From 060d6955e1271bc05e35e5e24b71e1b7b0e8eb17 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Sun, 9 Feb 2020 15:45:31 +0100 Subject: [PATCH 03/12] style: follow upstream code style --- application/MultiMC.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 039fb11d..45df5937 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -174,7 +174,7 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) // --alive parser.addSwitch("alive"); parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after MultiMC starts"); - + // --import parser.addOption("import"); parser.addShortOpt("import", 'I'); parser.addDocumentation("import", "Import instance from specified zip (local path or URL)"); @@ -818,8 +818,8 @@ void MultiMC::performMainStartupAction() showMainWindow(false); qDebug() << "<> Main window shown."; } - - if (!m_zipToImport.isEmpty()) { + if(!m_zipToImport.isEmpty()) + { qDebug() << "<> Importing instance from zip:" << m_zipToImport.toString(); QList urls = { m_zipToImport }; m_mainWindow->droppedURLs(urls); From 381c12547fe91a7392f42337674da390841b39ed Mon Sep 17 00:00:00 2001 From: OverMighty Date: Sun, 9 Feb 2020 16:17:41 +0100 Subject: [PATCH 04/12] feat: allow telling the main process to import a zip This commit enhances the IPC message system and adds a new IPC command in order to allow secondary MultiMC processes that were started by executing MultiMC with the `--import` command-line option to tell the main MutliMC process to open the "Import from zip" dialog window and prefill the URL field with the specified URL. --- application/MultiMC.cpp | 44 +++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 45df5937..393ea046 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -284,13 +284,20 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) connect(m_peerInstance, &LocalPeer::messageReceived, this, &MultiMC::messageReceived); if(m_peerInstance->isClient()) { + int timeout = 2000; + if(m_instanceIdToLaunch.isEmpty()) { - m_peerInstance->sendMessage("activate", 2000); + m_peerInstance->sendMessage("activate", timeout); + + if(!m_zipToImport.isEmpty()) + { + m_peerInstance->sendMessage("import " + m_zipToImport.toString(), timeout); + } } else { - m_peerInstance->sendMessage(m_instanceIdToLaunch, 2000); + m_peerInstance->sendMessage("launch " + m_instanceIdToLaunch, timeout); } m_status = MultiMC::Succeeded; return; @@ -820,9 +827,8 @@ void MultiMC::performMainStartupAction() } if(!m_zipToImport.isEmpty()) { - qDebug() << "<> Importing instance from zip:" << m_zipToImport.toString(); - QList urls = { m_zipToImport }; - m_mainWindow->droppedURLs(urls); + qDebug() << "<> Importing instance from zip:" << m_zipToImport; + m_mainWindow->droppedURLs({ m_zipToImport }); } } @@ -860,18 +866,40 @@ void MultiMC::messageReceived(const QString& message) qDebug() << "Received message" << message << "while still initializing. It will be ignored."; return; } - if(message == "activate") + + QStringList args = message.split(' '); + QString command = args.takeFirst(); + + if(command == "activate") { showMainWindow(); } - else + else if(command == "import") { - auto inst = instances()->getInstanceById(message); + if(args.isEmpty()) + { + qWarning() << "Received" << command << "message without a zip path/URL."; + return; + } + m_mainWindow->droppedURLs({ QUrl(args.takeFirst()) }); + } + else if(command == "launch") + { + if(args.isEmpty()) + { + qWarning() << "Received" << command << "message without an instance ID."; + return; + } + auto inst = instances()->getInstanceById(args.takeFirst()); if(inst) { launch(inst, true, nullptr); } } + else + { + qWarning() << "Received invalid message" << message; + } } void MultiMC::analyticsSettingChanged(const Setting&, QVariant value) From bbcacec6eca70fefcb6c7a3249586a8c7b2fb634 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Mon, 4 May 2020 11:37:02 +0200 Subject: [PATCH 05/12] fix: add support for args with spaces to MultiMC::messageReceived() Previously, when the main instance of MultiMC would receive an `import` or `launch` message from another instance, it would split the message on each space, and only read the first word of the argument (zip path/URL or instance ID). This commit fixes that problem by sectioning the message string instead. --- application/MultiMC.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 393ea046..86f426f8 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -867,8 +867,7 @@ void MultiMC::messageReceived(const QString& message) return; } - QStringList args = message.split(' '); - QString command = args.takeFirst(); + QString command = message.section(' ', 0, 0); if(command == "activate") { @@ -876,21 +875,23 @@ void MultiMC::messageReceived(const QString& message) } else if(command == "import") { - if(args.isEmpty()) + QString arg = message.section(' ', 1); + if(arg.isEmpty()) { qWarning() << "Received" << command << "message without a zip path/URL."; return; } - m_mainWindow->droppedURLs({ QUrl(args.takeFirst()) }); + m_mainWindow->droppedURLs({ QUrl(arg) }); } else if(command == "launch") { - if(args.isEmpty()) + QString arg = message.section(' ', 1); + if(arg.isEmpty()) { qWarning() << "Received" << command << "message without an instance ID."; return; } - auto inst = instances()->getInstanceById(args.takeFirst()); + auto inst = instances()->getInstanceById(arg); if(inst) { launch(inst, true, nullptr); From 997c25620a6d05ab6a700bdb4d39e58be5fdae92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 17 May 2020 13:59:30 +0200 Subject: [PATCH 06/12] GH-3131 fix not working with proxy ports > 32767 --- application/pages/global/ProxyPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/pages/global/ProxyPage.cpp b/application/pages/global/ProxyPage.cpp index ee56a54e..3f0e766b 100644 --- a/application/pages/global/ProxyPage.cpp +++ b/application/pages/global/ProxyPage.cpp @@ -95,7 +95,7 @@ void ProxyPage::loadSettings() ui->proxyHTTPBtn->setChecked(true); ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); - ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); + ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); ui->proxyUserEdit->setText(s->get("ProxyUser").toString()); ui->proxyPassEdit->setText(s->get("ProxyPass").toString()); } From 9eaa636908076d7b767e05e4dea4d579cfbbfd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 17 May 2020 19:56:59 +0200 Subject: [PATCH 07/12] GH-2802 remove extra remapping of indexes in VersionPage model --- application/pages/instance/VersionPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/pages/instance/VersionPage.cpp b/application/pages/instance/VersionPage.cpp index 60ff8301..c7a8dc30 100644 --- a/application/pages/instance/VersionPage.cpp +++ b/application/pages/instance/VersionPage.cpp @@ -61,7 +61,7 @@ public: virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override { - QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role); + QVariant var = QIdentityProxyModel::data(proxyIndex, role); int column = proxyIndex.column(); if(column == 0 && role == Qt::DecorationRole && m_parentWidget) { From e7f79c90764e03b3ba41af8352bdd167cd1db2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 19 May 2020 15:13:16 +0200 Subject: [PATCH 08/12] Remove some old forge hacks Forge apparently removed all `.pack.xz` files without warning. It broke a bunch of stuff, as always. But it also means we don't need some ugly code anymore. This is removed: - Support for 'forge-pack-xz' and the forge-specific file download compression. - The pack200 library we no longer need. This stays: - The LZMA decompression library - we may still want to use it. --- CMakeLists.txt | 1 - COPYING.md | 29 - api/logic/CMakeLists.txt | 6 +- api/logic/minecraft/Library.cpp | 31 +- api/logic/minecraft/MinecraftUpdate.cpp | 1 - api/logic/minecraft/forge/ForgeXzDownload.cpp | 393 -- api/logic/minecraft/forge/ForgeXzDownload.h | 61 - libraries/pack200/CMakeLists.txt | 50 - libraries/pack200/LICENSE | 347 -- libraries/pack200/anti200.cpp | 43 - libraries/pack200/include/unpack200.h | 37 - libraries/pack200/src/bands.cpp | 423 -- libraries/pack200/src/bands.h | 489 -- libraries/pack200/src/bytes.cpp | 217 - libraries/pack200/src/bytes.h | 286 - libraries/pack200/src/coding.cpp | 1044 ---- libraries/pack200/src/coding.h | 247 - libraries/pack200/src/constants.h | 442 -- libraries/pack200/src/defines.h | 65 - libraries/pack200/src/unpack.cpp | 4790 ----------------- libraries/pack200/src/unpack.h | 549 -- libraries/pack200/src/unpack200.cpp | 162 - libraries/pack200/src/utils.cpp | 71 - libraries/pack200/src/utils.h | 53 - libraries/pack200/src/zip.cpp | 589 -- libraries/pack200/src/zip.h | 112 - 26 files changed, 10 insertions(+), 10528 deletions(-) delete mode 100644 api/logic/minecraft/forge/ForgeXzDownload.cpp delete mode 100644 api/logic/minecraft/forge/ForgeXzDownload.h delete mode 100644 libraries/pack200/CMakeLists.txt delete mode 100644 libraries/pack200/LICENSE delete mode 100644 libraries/pack200/anti200.cpp delete mode 100644 libraries/pack200/include/unpack200.h delete mode 100644 libraries/pack200/src/bands.cpp delete mode 100644 libraries/pack200/src/bands.h delete mode 100644 libraries/pack200/src/bytes.cpp delete mode 100644 libraries/pack200/src/bytes.h delete mode 100644 libraries/pack200/src/coding.cpp delete mode 100644 libraries/pack200/src/coding.h delete mode 100644 libraries/pack200/src/constants.h delete mode 100644 libraries/pack200/src/defines.h delete mode 100644 libraries/pack200/src/unpack.cpp delete mode 100644 libraries/pack200/src/unpack.h delete mode 100644 libraries/pack200/src/unpack200.cpp delete mode 100644 libraries/pack200/src/utils.cpp delete mode 100644 libraries/pack200/src/utils.h delete mode 100644 libraries/pack200/src/zip.cpp delete mode 100644 libraries/pack200/src/zip.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d02dfc8b..747ec5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,6 @@ add_subdirectory(libraries/launcher) # java based launcher part for Minecraft add_subdirectory(libraries/javacheck) # java compatibility checker add_subdirectory(libraries/xz-embedded) # xz compression add_subdirectory(libraries/quazip) # zip manipulation library -add_subdirectory(libraries/pack200) # java pack200 compression add_subdirectory(libraries/rainbow) # Qt extension for colors add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions diff --git a/COPYING.md b/COPYING.md index 8aa7e75e..70ff7ce2 100644 --- a/COPYING.md +++ b/COPYING.md @@ -128,35 +128,6 @@ This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL -# Pack200 - - The GNU General Public License (GPL) - - Version 2, June 1991 - - + "CLASSPATH" EXCEPTION TO THE GPL - - Certain source files distributed by Oracle America and/or its affiliates are - subject to the following clarification and special exception to the GPL, but - only where Oracle has expressly included in the particular source file's header - the words "Oracle designates this particular file as subject to the "Classpath" - exception as provided by Oracle in the LICENSE file that accompanied this code." - - Linking this library statically or dynamically with other modules is making - a combined work based on this library. Thus, the terms and conditions of - the GNU General Public License cover the whole combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent modules, - and to copy and distribute the resulting executable under terms of your - choice, provided that you also meet, for each linked independent module, - the terms and conditions of the license of that module. An independent - module is a module which is not derived from or based on this library. If - you modify this library, you may extend this exception to your version of - the library, but you are not obligated to do so. If you do not wish to do - so, delete this exception statement from your version. - # Quazip Copyright (C) 2005-2011 Sergey A. Tachenov diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 995c9d4e..50c2cb6e 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -305,10 +305,6 @@ set(MINECRAFT_SOURCES minecraft/AssetsUtils.h minecraft/AssetsUtils.cpp - # Forge and all things forge related - minecraft/forge/ForgeXzDownload.h - minecraft/forge/ForgeXzDownload.cpp - # Skin upload utilities minecraft/SkinUpload.cpp minecraft/SkinUpload.h @@ -495,7 +491,7 @@ set_target_properties(MultiMC_logic PROPERTIES CXX_VISIBILITY_PRESET hidden VISI generate_export_header(MultiMC_logic) # Link -target_link_libraries(MultiMC_logic xz-embedded MultiMC_unpack200 systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES}) +target_link_libraries(MultiMC_logic systeminfo MultiMC_quazip MultiMC_classparser ${NBT_NAME} ${ZLIB_LIBRARIES}) target_link_libraries(MultiMC_logic Qt5::Core Qt5::Xml Qt5::Network Qt5::Concurrent) # Mark and export headers diff --git a/api/logic/minecraft/Library.cpp b/api/logic/minecraft/Library.cpp index a56e8110..9ff8dcdc 100644 --- a/api/logic/minecraft/Library.cpp +++ b/api/logic/minecraft/Library.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -88,26 +87,19 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads( { options |= Net::Download::Option::AcceptLocalFiles; } - if (isForge()) + + if(sha1.size()) { - qDebug() << "XzDownload for:" << rawName() << "storage:" << storage << "url:" << url; - out.append(ForgeXzDownload::make(url, storage, entry)); + auto rawSha1 = QByteArray::fromHex(sha1.toLatin1()); + auto dl = Net::Download::makeCached(url, entry, options); + dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); + qDebug() << "Checksummed Download for:" << rawName() << "storage:" << storage << "url:" << url; + out.append(dl); } else { - if(sha1.size()) - { - auto rawSha1 = QByteArray::fromHex(sha1.toLatin1()); - auto dl = Net::Download::makeCached(url, entry, options); - dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); - qDebug() << "Checksummed Download for:" << rawName() << "storage:" << storage << "url:" << url; - out.append(dl); - } - else - { - out.append(Net::Download::makeCached(url, entry, options)); - qDebug() << "Download for:" << rawName() << "storage:" << storage << "url:" << url; - } + out.append(Net::Download::makeCached(url, entry, options)); + qDebug() << "Download for:" << rawName() << "storage:" << storage << "url:" << url; } return true; }; @@ -243,11 +235,6 @@ bool Library::isAlwaysStale() const return m_hint == "always-stale"; } -bool Library::isForge() const -{ - return m_hint == "forge-pack-xz"; -} - void Library::setStoragePrefix(QString prefix) { m_storagePrefix = prefix; diff --git a/api/logic/minecraft/MinecraftUpdate.cpp b/api/logic/minecraft/MinecraftUpdate.cpp index 00558e37..f9ff114d 100644 --- a/api/logic/minecraft/MinecraftUpdate.cpp +++ b/api/logic/minecraft/MinecraftUpdate.cpp @@ -14,7 +14,6 @@ */ #include "Env.h" -#include #include "MinecraftUpdate.h" #include "MinecraftInstance.h" diff --git a/api/logic/minecraft/forge/ForgeXzDownload.cpp b/api/logic/minecraft/forge/ForgeXzDownload.cpp deleted file mode 100644 index c6465469..00000000 --- a/api/logic/minecraft/forge/ForgeXzDownload.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/* Copyright 2013-2019 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Env.h" -#include "ForgeXzDownload.h" -#include - -#include -#include -#include -#include -#include - -ForgeXzDownload::ForgeXzDownload(QString url, QString relative_path, MetaEntryPtr entry) : NetAction() -{ - m_entry = entry; - m_target_path = entry->getFullPath(); - m_pack200_xz_file.setFileTemplate("./dl_temp.XXXXXX"); - m_status = Job_NotStarted; - m_url_path = relative_path; - m_url = url + ".pack.xz"; -} - -void ForgeXzDownload::start() -{ - if(m_status == Job_Aborted) - { - qWarning() << "Attempt to start an aborted Download:" << m_url.toString(); - emit aborted(m_index_within_job); - return; - } - m_status = Job_InProgress; - if (!m_entry->isStale()) - { - m_status = Job_Finished; - emit succeeded(m_index_within_job); - return; - } - // can we actually create the real, final file? - if (!FS::ensureFilePathExists(m_target_path)) - { - m_status = Job_Failed; - emit failed(m_index_within_job); - return; - } - - qDebug() << "Downloading " << m_url.toString(); - QNetworkRequest request(m_url); - request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->getETag().toLatin1()); - request.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Cached)"); - - QNetworkReply *rep = ENV.qnam().get(request); - - m_reply.reset(rep); - connect(rep, SIGNAL(downloadProgress(qint64, qint64)), SLOT(downloadProgress(qint64, qint64))); - connect(rep, SIGNAL(finished()), SLOT(downloadFinished())); - connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError))); - connect(rep, SIGNAL(readyRead()), SLOT(downloadReadyRead())); -} - -void ForgeXzDownload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) -{ - m_total_progress = bytesTotal; - m_progress = bytesReceived; - emit netActionProgress(m_index_within_job, bytesReceived, bytesTotal); -} - -void ForgeXzDownload::downloadError(QNetworkReply::NetworkError error) -{ - if(error == QNetworkReply::OperationCanceledError) - { - qCritical() << "Aborted " << m_url.toString(); - m_status = Job_Aborted; - } - else - { - // error happened during download. - qCritical() << "Failed " << m_url.toString() << " with reason " << error; - m_status = Job_Failed; - } -} - -void ForgeXzDownload::failAndTryNextMirror() -{ - m_status = Job_Failed; - emit failed(m_index_within_job); -} - -void ForgeXzDownload::downloadFinished() -{ - // if the download succeeded - if (m_status != Job_Failed && m_status != Job_Aborted) - { - // nothing went wrong... - m_status = Job_Finished; - if (m_pack200_xz_file.isOpen()) - { - // we actually downloaded something! process and isntall it - decompressAndInstall(); - return; - } - else - { - // something bad happened -- on the local machine! - m_status = Job_Failed; - m_pack200_xz_file.remove(); - m_reply.reset(); - emit failed(m_index_within_job); - return; - } - } - else if(m_status == Job_Aborted) - { - m_pack200_xz_file.remove(); - m_reply.reset(); - emit failed(m_index_within_job); - emit aborted(m_index_within_job); - return; - } - // else the download failed - else - { - m_status = Job_Failed; - m_pack200_xz_file.close(); - m_pack200_xz_file.remove(); - m_reply.reset(); - failAndTryNextMirror(); - return; - } -} - -void ForgeXzDownload::downloadReadyRead() -{ - - if (!m_pack200_xz_file.isOpen()) - { - if (!m_pack200_xz_file.open()) - { - /* - * Can't open the file... the job failed - */ - m_reply->abort(); - emit failed(m_index_within_job); - return; - } - } - m_pack200_xz_file.write(m_reply->readAll()); -} - -#include "xz.h" -#include "unpack200.h" -#include -#include - -const size_t buffer_size = 8196; - -// NOTE: once this gets here, it can't be aborted anymore. we don't care. -void ForgeXzDownload::decompressAndInstall() -{ - // rewind the downloaded temp file - m_pack200_xz_file.seek(0); - // de-xz'd file - QTemporaryFile pack200_file("./dl_temp.XXXXXX"); - pack200_file.open(); - - bool xz_success = false; - // first, de-xz - { - uint8_t in[buffer_size]; - uint8_t out[buffer_size]; - struct xz_buf b; - struct xz_dec *s; - enum xz_ret ret; - xz_crc32_init(); - xz_crc64_init(); - s = xz_dec_init(XZ_DYNALLOC, 1 << 26); - if (s == nullptr) - { - xz_dec_end(s); - failAndTryNextMirror(); - return; - } - b.in = in; - b.in_pos = 0; - b.in_size = 0; - b.out = out; - b.out_pos = 0; - b.out_size = buffer_size; - while (!xz_success) - { - if (b.in_pos == b.in_size) - { - b.in_size = m_pack200_xz_file.read((char *)in, sizeof(in)); - b.in_pos = 0; - } - - ret = xz_dec_run(s, &b); - - if (b.out_pos == sizeof(out)) - { - auto wresult = pack200_file.write((char *)out, b.out_pos); - if (wresult < 0 || size_t(wresult) != b.out_pos) - { - // msg = "Write error\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - } - - b.out_pos = 0; - } - - if (ret == XZ_OK) - continue; - - if (ret == XZ_UNSUPPORTED_CHECK) - { - // unsupported check. this is OK, but we should log this - continue; - } - - auto wresult = pack200_file.write((char *)out, b.out_pos); - if (wresult < 0 || size_t(wresult) != b.out_pos) - { - // write error - pack200_file.close(); - xz_dec_end(s); - return; - } - - switch (ret) - { - case XZ_STREAM_END: - xz_dec_end(s); - xz_success = true; - break; - - case XZ_MEM_ERROR: - qCritical() << "Memory allocation failed\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - - case XZ_MEMLIMIT_ERROR: - qCritical() << "Memory usage limit reached\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - - case XZ_FORMAT_ERROR: - qCritical() << "Not a .xz file\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - - case XZ_OPTIONS_ERROR: - qCritical() << "Unsupported options in the .xz headers\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - - case XZ_DATA_ERROR: - case XZ_BUF_ERROR: - qCritical() << "File is corrupt\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - - default: - qCritical() << "Bug!\n"; - xz_dec_end(s); - failAndTryNextMirror(); - return; - } - } - } - m_pack200_xz_file.remove(); - - // revert pack200 - pack200_file.seek(0); - int handle_in = pack200_file.handle(); - // FIXME: dispose of file handles, pointers and the like. Ideally wrap in objects. - if(handle_in == -1) - { - qCritical() << "Error reopening " << pack200_file.fileName(); - failAndTryNextMirror(); - return; - } - int handle_in_dup = dup (handle_in); - if(handle_in_dup == -1) - { - qCritical() << "Error reopening " << pack200_file.fileName(); - failAndTryNextMirror(); - return; - } - FILE *file_in = fdopen (handle_in_dup, "rb"); - if(!file_in) - { - qCritical() << "Error reopening " << pack200_file.fileName(); - failAndTryNextMirror(); - return; - } - QFile qfile_out(m_target_path); - if(!qfile_out.open(QIODevice::WriteOnly)) - { - qCritical() << "Error opening " << qfile_out.fileName(); - failAndTryNextMirror(); - return; - } - int handle_out = qfile_out.handle(); - if(handle_out == -1) - { - qCritical() << "Error opening " << qfile_out.fileName(); - failAndTryNextMirror(); - return; - } - int handle_out_dup = dup (handle_out); - if(handle_out_dup == -1) - { - qCritical() << "Error reopening " << qfile_out.fileName(); - failAndTryNextMirror(); - return; - } - FILE *file_out = fdopen (handle_out_dup, "wb"); - if(!file_out) - { - qCritical() << "Error opening " << qfile_out.fileName(); - failAndTryNextMirror(); - return; - } - try - { - // NOTE: this takes ownership of both FILE pointers. That's why we duplicate them above. - unpack_200(file_in, file_out); - } - catch (const std::runtime_error &err) - { - m_status = Job_Failed; - qCritical() << "Error unpacking " << pack200_file.fileName() << " : " << err.what(); - QFile f(m_target_path); - if (f.exists()) - f.remove(); - failAndTryNextMirror(); - return; - } - pack200_file.remove(); - - QFile jar_file(m_target_path); - - if (!jar_file.open(QIODevice::ReadOnly)) - { - jar_file.remove(); - failAndTryNextMirror(); - return; - } - auto hash = QCryptographicHash::hash(jar_file.readAll(), QCryptographicHash::Md5); - m_entry->setMD5Sum(hash.toHex().constData()); - jar_file.close(); - - QFileInfo output_file_info(m_target_path); - m_entry->setETag(m_reply->rawHeader("ETag").constData()); - m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch()); - m_entry->setStale(false); - ENV.metacache()->updateEntry(m_entry); - - m_reply.reset(); - emit succeeded(m_index_within_job); -} - -bool ForgeXzDownload::abort() -{ - if(m_reply) - m_reply->abort(); - m_status = Job_Aborted; - return true; -} - -bool ForgeXzDownload::canAbort() -{ - return true; -} diff --git a/api/logic/minecraft/forge/ForgeXzDownload.h b/api/logic/minecraft/forge/ForgeXzDownload.h deleted file mode 100644 index 63e75f71..00000000 --- a/api/logic/minecraft/forge/ForgeXzDownload.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright 2013-2019 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "net/NetAction.h" -#include "net/HttpMetaCache.h" -#include -#include - -typedef std::shared_ptr ForgeXzDownloadPtr; - -class ForgeXzDownload : public NetAction -{ - Q_OBJECT -public: - MetaEntryPtr m_entry; - /// if saving to file, use the one specified in this string - QString m_target_path; - /// this is the output file, if any - QTemporaryFile m_pack200_xz_file; - /// path relative to the mirror base - QString m_url_path; - -public: - explicit ForgeXzDownload(QString url, QString relative_path, MetaEntryPtr entry); - static ForgeXzDownloadPtr make(QString url, QString relative_path, MetaEntryPtr entry) - { - return ForgeXzDownloadPtr(new ForgeXzDownload(url, relative_path, entry)); - } - virtual ~ForgeXzDownload(){}; - bool canAbort() override; - -protected -slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void downloadFinished() override; - void downloadReadyRead() override; - -public -slots: - void start() override; - bool abort() override; - -private: - void decompressAndInstall(); - void failAndTryNextMirror(); -}; diff --git a/libraries/pack200/CMakeLists.txt b/libraries/pack200/CMakeLists.txt deleted file mode 100644 index 31eb0f73..00000000 --- a/libraries/pack200/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -cmake_minimum_required(VERSION 3.1) - -project(MultiMC_unpack200) - -option(PACK200_BUILD_BINARY "Build a tiny utility that decompresses pack200 streams" OFF) - -# Find ZLIB for quazip -find_package(ZLIB REQUIRED) - -set(PACK200_SRC - include/unpack200.h - src/bands.cpp - src/bands.h - src/bytes.cpp - src/bytes.h - src/coding.cpp - src/coding.h - src/constants.h - src/defines.h - src/unpack200.cpp - src/unpack.cpp - src/unpack.h - src/utils.cpp - src/utils.h - src/zip.cpp - src/zip.h -) - -if (Qt5_POSITION_INDEPENDENT_CODE) - SET(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif() - -add_library(MultiMC_unpack200 SHARED ${PACK200_SRC}) -target_include_directories(MultiMC_unpack200 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}" PRIVATE ${ZLIB_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/src") -target_link_libraries(MultiMC_unpack200 ${ZLIB_LIBRARIES}) - -set_target_properties(MultiMC_unpack200 PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1) -generate_export_header(MultiMC_unpack200) - -# Install it -install( - TARGETS MultiMC_unpack200 - RUNTIME DESTINATION ${LIBRARY_DEST_DIR} - LIBRARY DESTINATION ${LIBRARY_DEST_DIR} -) - -if(PACK200_BUILD_BINARY) - add_executable(anti200 anti200.cpp) - target_link_libraries(anti200 MultiMC_unpack200) -endif() diff --git a/libraries/pack200/LICENSE b/libraries/pack200/LICENSE deleted file mode 100644 index b40a0f45..00000000 --- a/libraries/pack200/LICENSE +++ /dev/null @@ -1,347 +0,0 @@ -The GNU General Public License (GPL) - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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. - -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) - - 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., 59 - Temple Place, Suite 330, Boston, MA 02111-1307 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 Library General Public -License instead of this License. - - -"CLASSPATH" EXCEPTION TO THE GPL - -Certain source files distributed by Oracle America and/or its affiliates are -subject to the following clarification and special exception to the GPL, but -only where Oracle has expressly included in the particular source file's header -the words "Oracle designates this particular file as subject to the "Classpath" -exception as provided by Oracle in the LICENSE file that accompanied this code." - - Linking this library statically or dynamically with other modules is making - a combined work based on this library. Thus, the terms and conditions of - the GNU General Public License cover the whole combination. - - As a special exception, the copyright holders of this library give you - permission to link this library with independent modules to produce an - executable, regardless of the license terms of these independent modules, - and to copy and distribute the resulting executable under terms of your - choice, provided that you also meet, for each linked independent module, - the terms and conditions of the license of that module. An independent - module is a module which is not derived from or based on this library. If - you modify this library, you may extend this exception to your version of - the library, but you are not obligated to do so. If you do not wish to do - so, delete this exception statement from your version. diff --git a/libraries/pack200/anti200.cpp b/libraries/pack200/anti200.cpp deleted file mode 100644 index 1e672847..00000000 --- a/libraries/pack200/anti200.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This is trivial. Do what thou wilt with it. Public domain. - */ - -#include -#include -#include "unpack200.h" - -int main(int argc, char **argv) -{ - if (argc != 3) - { - std::cerr << "Simple pack200 unpacker!" << std::endl << "Run like this:" << std::endl - << " " << argv[0] << " input.jar.lzma output.jar" << std::endl; - return EXIT_FAILURE; - } - - FILE *input = fopen(argv[1], "rb"); - if (!input) - { - std::cerr << "Can't open input file"; - return EXIT_FAILURE; - } - FILE *output = fopen(argv[2], "wb"); - if (!output) - { - fclose(input); - std::cerr << "Can't open output file"; - return EXIT_FAILURE; - } - try - { - unpack_200(input, output); - } - catch (const std::runtime_error &e) - { - std::cerr << "Bad things happened: " << e.what() << std::endl; - fclose(input); - fclose(output); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/libraries/pack200/include/unpack200.h b/libraries/pack200/include/unpack200.h deleted file mode 100644 index 30ce6656..00000000 --- a/libraries/pack200/include/unpack200.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#pragma once - -#include "multimc_unpack200_export.h" - -/** - * @brief Unpack a PACK200 file - * - * @param input_path Path to the input file in PACK200 format. System native string encoding. - * @param output_path Path to the output file in PACK200 format. System native string encoding. - * @throw std::runtime_error for any error encountered - */ -MULTIMC_UNPACK200_EXPORT void unpack_200(FILE * input_path, FILE * output_path); diff --git a/libraries/pack200/src/bands.cpp b/libraries/pack200/src/bands.cpp deleted file mode 100644 index e82613b5..00000000 --- a/libraries/pack200/src/bands.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// -*- C++ -*- -// Small program for unpacking specially compressed Java packages. -// John R. Rose - -#include - -#include -#include -#include -#include -#include -#include - -#include "defines.h" -#include "bytes.h" -#include "utils.h" -#include "coding.h" -#include "bands.h" - -#include "constants.h" -#include "unpack.h" - -void band::readData(int expectedLength) -{ - assert(expectedLength >= 0); - assert(vs[0].cmk == cmk_ERROR); - if (expectedLength != 0) - { - assert(length == 0); - length = expectedLength; - } - if (length == 0) - { - assert((rplimit = cm.vs0.rp = u->rp) != nullptr); - return; - } - assert(length > 0); - - bool is_BYTE1 = (defc->spec == BYTE1_spec); - - if (is_BYTE1) - { - // No possibility of coding change. Sizing is exact. - u->ensure_input(length); - } - else - { - // Make a conservatively generous estimate of band size in bytes. - // Assume B == 5 everywhere. - // Assume awkward pop with all {U} values (2*5 per value) - int64_t generous = (int64_t)length * (B_MAX * 3 + 1) + C_SLOP; - u->ensure_input(generous); - } - - // Read one value to see what it might be. - int XB = _meta_default; - if (!is_BYTE1) - { - // must be a variable-length coding - assert(defc->B() > 1 && defc->L() > 0); - - value_stream xvs; - coding *valc = defc; - if (valc->D() != 0) - { - valc = coding::findBySpec(defc->B(), defc->H(), defc->S()); - assert(!valc->isMalloc); - } - xvs.init(u->rp, u->rplimit, valc); - int X = xvs.getInt(); - if (valc->S() != 0) - { - assert(valc->min <= -256); - XB = -1 - X; - } - else - { - int L = valc->L(); - assert(valc->max >= L + 255); - XB = X - L; - } - if (0 <= XB && XB < 256) - { - // Skip over the escape value. - u->rp = xvs.rp; - } - else - { - // No, it's still default. - XB = _meta_default; - } - } - - if (XB <= _meta_canon_max) - { - byte XB_byte = (byte)XB; - byte *XB_ptr = &XB_byte; - cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, nullptr); - } - else - { - assert(u->meta_rp != nullptr); - // Scribble the initial byte onto the band. - byte *save_meta_rp = --u->meta_rp; - byte save_meta_xb = (*save_meta_rp); - (*save_meta_rp) = (byte)XB; - cm.init(u->rp, u->rplimit, u->meta_rp, 0, defc, length, nullptr); - (*save_meta_rp) = save_meta_xb; // put it back, just to be tidy - } - rplimit = u->rp; - - rewind(); -} - -void band::setIndex(cpindex *ix_) -{ - assert(ix_ == nullptr || ixTag == ix_->ixTag); - ix = ix_; -} -void band::setIndexByTag(byte tag) -{ - setIndex(u->cp.getIndex(tag)); -} - -entry *band::getRefCommon(cpindex *ix_, bool nullOKwithCaller) -{ - assert(ix_->ixTag == ixTag || - (ixTag == CONSTANT_Literal && ix_->ixTag >= CONSTANT_Integer && - ix_->ixTag <= CONSTANT_String)); - int n = vs[0].getInt() - nullOK; - // Note: band-local nullOK means nullptr encodes as 0. - // But nullOKwithCaller means caller is willing to tolerate a nullptr. - entry *ref = ix_->get(n); - if (ref == nullptr && !(nullOKwithCaller && n == -1)) - unpack_abort(n == -1 ? "nullptr ref" : "bad ref"); - return ref; -} - -int64_t band::getLong(band &lo_band, bool have_hi) -{ - band &hi_band = (*this); - assert(lo_band.bn == hi_band.bn + 1); - uint32_t lo = lo_band.getInt(); - if (!have_hi) - { - assert(hi_band.length == 0); - return makeLong(0, lo); - } - uint32_t hi = hi_band.getInt(); - return makeLong(hi, lo); -} - -int band::getIntTotal() -{ - if (length == 0) - return 0; - if (total_memo > 0) - return total_memo - 1; - int total = getInt(); - // overflow checks require that none of the addends are <0, - // and that the partial sums never overflow (wrap negative) - if (total < 0) - { - unpack_abort("overflow detected"); - } - for (int k = length - 1; k > 0; k--) - { - int prev_total = total; - total += vs[0].getInt(); - if (total < prev_total) - { - unpack_abort("overflow detected"); - } - } - rewind(); - total_memo = total + 1; - return total; -} - -int band::getIntCount(int tag) -{ - if (length == 0) - return 0; - if (tag >= HIST0_MIN && tag <= HIST0_MAX) - { - if (hist0 == nullptr) - { - // Lazily calculate an approximate histogram. - hist0 = U_NEW(int, (HIST0_MAX - HIST0_MIN) + 1); - for (int k = length; k > 0; k--) - { - int x = vs[0].getInt(); - if (x >= HIST0_MIN && x <= HIST0_MAX) - hist0[x - HIST0_MIN] += 1; - } - rewind(); - } - return hist0[tag - HIST0_MIN]; - } - int total = 0; - for (int k = length; k > 0; k--) - { - total += (vs[0].getInt() == tag) ? 1 : 0; - } - rewind(); - return total; -} - -#define INDEX_INIT(tag, nullOK, subindex) ((tag) + (subindex) * SUBINDEX_BIT + (nullOK) * 256) - -#define INDEX(tag) INDEX_INIT(tag, 0, 0) -#define NULL_OR_INDEX(tag) INDEX_INIT(tag, 1, 0) -#define SUB_INDEX(tag) INDEX_INIT(tag, 0, 1) -#define NO_INDEX 0 - -struct band_init -{ - int defc; - int index; -}; - -#define BAND_INIT(name, cspec, ix) \ - { \ - cspec, ix \ - } - -const band_init all_band_inits[] = - { - // BAND_INIT(archive_magic, BYTE1_spec, 0), - // BAND_INIT(archive_header, UNSIGNED5_spec, 0), - // BAND_INIT(band_headers, BYTE1_spec, 0), - BAND_INIT(cp_Utf8_prefix, DELTA5_spec, 0), BAND_INIT(cp_Utf8_suffix, UNSIGNED5_spec, 0), - BAND_INIT(cp_Utf8_chars, CHAR3_spec, 0), BAND_INIT(cp_Utf8_big_suffix, DELTA5_spec, 0), - BAND_INIT(cp_Utf8_big_chars, DELTA5_spec, 0), BAND_INIT(cp_Int, UDELTA5_spec, 0), - BAND_INIT(cp_Float, UDELTA5_spec, 0), BAND_INIT(cp_Long_hi, UDELTA5_spec, 0), - BAND_INIT(cp_Long_lo, DELTA5_spec, 0), BAND_INIT(cp_Double_hi, UDELTA5_spec, 0), - BAND_INIT(cp_Double_lo, DELTA5_spec, 0), - BAND_INIT(cp_String, UDELTA5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(cp_Class, UDELTA5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(cp_Signature_form, DELTA5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(cp_Signature_classes, UDELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(cp_Descr_name, DELTA5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(cp_Descr_type, UDELTA5_spec, INDEX(CONSTANT_Signature)), - BAND_INIT(cp_Field_class, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(cp_Field_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), - BAND_INIT(cp_Method_class, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(cp_Method_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), - BAND_INIT(cp_Imethod_class, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(cp_Imethod_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)), - BAND_INIT(attr_definition_headers, BYTE1_spec, 0), - BAND_INIT(attr_definition_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(attr_definition_layout, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(ic_this_class, UDELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(ic_flags, UNSIGNED5_spec, 0), - BAND_INIT(ic_outer_class, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Class)), - BAND_INIT(ic_name, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), - BAND_INIT(class_this, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(class_super, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(class_interface_count, DELTA5_spec, 0), - BAND_INIT(class_interface, DELTA5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(class_field_count, DELTA5_spec, 0), - BAND_INIT(class_method_count, DELTA5_spec, 0), - BAND_INIT(field_descr, DELTA5_spec, INDEX(CONSTANT_NameandType)), - BAND_INIT(field_flags_hi, UNSIGNED5_spec, 0), - BAND_INIT(field_flags_lo, UNSIGNED5_spec, 0), - BAND_INIT(field_attr_count, UNSIGNED5_spec, 0), - BAND_INIT(field_attr_indexes, UNSIGNED5_spec, 0), - BAND_INIT(field_attr_calls, UNSIGNED5_spec, 0), - BAND_INIT(field_ConstantValue_KQ, UNSIGNED5_spec, INDEX(CONSTANT_Literal)), - BAND_INIT(field_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), - BAND_INIT(field_metadata_bands, -1, -1), BAND_INIT(field_attr_bands, -1, -1), - BAND_INIT(method_descr, MDELTA5_spec, INDEX(CONSTANT_NameandType)), - BAND_INIT(method_flags_hi, UNSIGNED5_spec, 0), - BAND_INIT(method_flags_lo, UNSIGNED5_spec, 0), - BAND_INIT(method_attr_count, UNSIGNED5_spec, 0), - BAND_INIT(method_attr_indexes, UNSIGNED5_spec, 0), - BAND_INIT(method_attr_calls, UNSIGNED5_spec, 0), - BAND_INIT(method_Exceptions_N, UNSIGNED5_spec, 0), - BAND_INIT(method_Exceptions_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(method_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), - BAND_INIT(method_metadata_bands, -1, -1), BAND_INIT(method_attr_bands, -1, -1), - BAND_INIT(class_flags_hi, UNSIGNED5_spec, 0), - BAND_INIT(class_flags_lo, UNSIGNED5_spec, 0), - BAND_INIT(class_attr_count, UNSIGNED5_spec, 0), - BAND_INIT(class_attr_indexes, UNSIGNED5_spec, 0), - BAND_INIT(class_attr_calls, UNSIGNED5_spec, 0), - BAND_INIT(class_SourceFile_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), - BAND_INIT(class_EnclosingMethod_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(class_EnclosingMethod_RDN, UNSIGNED5_spec, - NULL_OR_INDEX(CONSTANT_NameandType)), - BAND_INIT(class_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), - BAND_INIT(class_metadata_bands, -1, -1), - BAND_INIT(class_InnerClasses_N, UNSIGNED5_spec, 0), - BAND_INIT(class_InnerClasses_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(class_InnerClasses_F, UNSIGNED5_spec, 0), - BAND_INIT(class_InnerClasses_outer_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), - BAND_INIT(class_InnerClasses_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)), - BAND_INIT(class_ClassFile_version_minor_H, UNSIGNED5_spec, 0), - BAND_INIT(class_ClassFile_version_major_H, UNSIGNED5_spec, 0), - BAND_INIT(class_attr_bands, -1, -1), BAND_INIT(code_headers, BYTE1_spec, 0), - BAND_INIT(code_max_stack, UNSIGNED5_spec, 0), - BAND_INIT(code_max_na_locals, UNSIGNED5_spec, 0), - BAND_INIT(code_handler_count, UNSIGNED5_spec, 0), - BAND_INIT(code_handler_start_P, BCI5_spec, 0), - BAND_INIT(code_handler_end_PO, BRANCH5_spec, 0), - BAND_INIT(code_handler_catch_PO, BRANCH5_spec, 0), - BAND_INIT(code_handler_class_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), - BAND_INIT(code_flags_hi, UNSIGNED5_spec, 0), - BAND_INIT(code_flags_lo, UNSIGNED5_spec, 0), - BAND_INIT(code_attr_count, UNSIGNED5_spec, 0), - BAND_INIT(code_attr_indexes, UNSIGNED5_spec, 0), - BAND_INIT(code_attr_calls, UNSIGNED5_spec, 0), - BAND_INIT(code_StackMapTable_N, UNSIGNED5_spec, 0), - BAND_INIT(code_StackMapTable_frame_T, BYTE1_spec, 0), - BAND_INIT(code_StackMapTable_local_N, UNSIGNED5_spec, 0), - BAND_INIT(code_StackMapTable_stack_N, UNSIGNED5_spec, 0), - BAND_INIT(code_StackMapTable_offset, UNSIGNED5_spec, 0), - BAND_INIT(code_StackMapTable_T, BYTE1_spec, 0), - BAND_INIT(code_StackMapTable_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)), - BAND_INIT(code_StackMapTable_P, BCI5_spec, 0), - BAND_INIT(code_LineNumberTable_N, UNSIGNED5_spec, 0), - BAND_INIT(code_LineNumberTable_bci_P, BCI5_spec, 0), - BAND_INIT(code_LineNumberTable_line, UNSIGNED5_spec, 0), - BAND_INIT(code_LocalVariableTable_N, UNSIGNED5_spec, 0), - BAND_INIT(code_LocalVariableTable_bci_P, BCI5_spec, 0), - BAND_INIT(code_LocalVariableTable_span_O, BRANCH5_spec, 0), - BAND_INIT(code_LocalVariableTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(code_LocalVariableTable_type_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)), - BAND_INIT(code_LocalVariableTable_slot, UNSIGNED5_spec, 0), - BAND_INIT(code_LocalVariableTypeTable_N, UNSIGNED5_spec, 0), - BAND_INIT(code_LocalVariableTypeTable_bci_P, BCI5_spec, 0), - BAND_INIT(code_LocalVariableTypeTable_span_O, BRANCH5_spec, 0), - BAND_INIT(code_LocalVariableTypeTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(code_LocalVariableTypeTable_type_RS, UNSIGNED5_spec, - INDEX(CONSTANT_Signature)), - BAND_INIT(code_LocalVariableTypeTable_slot, UNSIGNED5_spec, 0), - BAND_INIT(code_attr_bands, -1, -1), BAND_INIT(bc_codes, BYTE1_spec, 0), - BAND_INIT(bc_case_count, UNSIGNED5_spec, 0), BAND_INIT(bc_case_value, DELTA5_spec, 0), - BAND_INIT(bc_byte, BYTE1_spec, 0), BAND_INIT(bc_short, DELTA5_spec, 0), - BAND_INIT(bc_local, UNSIGNED5_spec, 0), BAND_INIT(bc_label, BRANCH5_spec, 0), - BAND_INIT(bc_intref, DELTA5_spec, INDEX(CONSTANT_Integer)), - BAND_INIT(bc_floatref, DELTA5_spec, INDEX(CONSTANT_Float)), - BAND_INIT(bc_longref, DELTA5_spec, INDEX(CONSTANT_Long)), - BAND_INIT(bc_doubleref, DELTA5_spec, INDEX(CONSTANT_Double)), - BAND_INIT(bc_stringref, DELTA5_spec, INDEX(CONSTANT_String)), - BAND_INIT(bc_classref, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)), - BAND_INIT(bc_fieldref, DELTA5_spec, INDEX(CONSTANT_Fieldref)), - BAND_INIT(bc_methodref, UNSIGNED5_spec, INDEX(CONSTANT_Methodref)), - BAND_INIT(bc_imethodref, DELTA5_spec, INDEX(CONSTANT_InterfaceMethodref)), - BAND_INIT(bc_thisfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), - BAND_INIT(bc_superfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)), - BAND_INIT(bc_thismethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), - BAND_INIT(bc_supermethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), - BAND_INIT(bc_initref, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)), - BAND_INIT(bc_escref, UNSIGNED5_spec, INDEX(CONSTANT_All)), - BAND_INIT(bc_escrefsize, UNSIGNED5_spec, 0), BAND_INIT(bc_escsize, UNSIGNED5_spec, 0), - BAND_INIT(bc_escbyte, BYTE1_spec, 0), - BAND_INIT(file_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)), - BAND_INIT(file_size_hi, UNSIGNED5_spec, 0), BAND_INIT(file_size_lo, UNSIGNED5_spec, 0), - BAND_INIT(file_modtime, DELTA5_spec, 0), BAND_INIT(file_options, UNSIGNED5_spec, 0), - // BAND_INIT(file_bits, BYTE1_spec, 0), - {0, 0}}; - -band *band::makeBands(unpacker *u) -{ - band *tmp_all_bands = U_NEW(band, BAND_LIMIT); - for (int i = 0; i < BAND_LIMIT; i++) - { - assert((byte *)&all_band_inits[i + 1] < - (byte *)all_band_inits + sizeof(all_band_inits)); - const band_init &bi = all_band_inits[i]; - band &b = tmp_all_bands[i]; - coding *defc = coding::findBySpec(bi.defc); - assert((defc == nullptr) == (bi.defc == -1)); // no garbage, please - assert(defc == nullptr || !defc->isMalloc); - b.init(u, i, defc); - if (bi.index > 0) - { - b.nullOK = ((bi.index >> 8) & 1); - b.ixTag = (bi.index & 0xFF); - } - } - return tmp_all_bands; -} - -void band::initIndexes(unpacker *u) -{ - band *tmp_all_bands = u->all_bands; - for (int i = 0; i < BAND_LIMIT; i++) - { - band *scan = &tmp_all_bands[i]; - uint32_t tag = scan->ixTag; // Cf. #define INDEX(tag) above - if (tag != 0 && tag != CONSTANT_Literal && (tag & SUBINDEX_BIT) == 0) - { - scan->setIndex(u->cp.getIndex(tag)); - } - } -} diff --git a/libraries/pack200/src/bands.h b/libraries/pack200/src/bands.h deleted file mode 100644 index 66c5aec4..00000000 --- a/libraries/pack200/src/bands.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// -*- C++ -*- -struct entry; -struct cpindex; -struct unpacker; - -struct band -{ - int bn; // band_number of this band - coding *defc; // default coding method - cpindex *ix; // CP entry mapping, if CPRefBand - byte ixTag; // 0 or 1; nullptr is coded as (nullOK?0:-1) - byte nullOK; // 0 or 1; nullptr is coded as (nullOK?0:-1) - int length; // expected # values - unpacker *u; // back pointer - - value_stream vs[2]; // source of values - coding_method cm; // method used for initial state of vs[0] - byte *rplimit; // end of band (encoded, transmitted) - - int total_memo; // cached value of getIntTotal, or -1 - int *hist0; // approximate. histogram - enum - { - HIST0_MIN = 0, - HIST0_MAX = 255 - }; // catches the usual cases - - // properties for attribute layout elements: - byte le_kind; // EK_XXX - byte le_bci; // 0,EK_BCI,EK_BCD,EK_BCO - byte le_back; // ==EF_BACK - byte le_len; // 0,1,2,4 (size in classfile), or call addr - band **le_body; // body of repl, union, call (nullptr-terminated) -// Note: EK_CASE elements use hist0 to record union tags. -#define le_casetags hist0 - - band &nextBand() - { - return this[1]; - } - band &prevBand() - { - return this[-1]; - } - - void init(unpacker *u_, int bn_, coding *defc_) - { - u = u_; - cm.u = u_; - bn = bn_; - defc = defc_; - } - void init(unpacker *u_, int bn_, int defcSpec) - { - init(u_, bn_, coding::findBySpec(defcSpec)); - } - void initRef(int ixTag_ = 0, bool nullOK_ = false) - { - ixTag = ixTag_; - nullOK = nullOK_; - setIndexByTag(ixTag); - } - - void expectMoreLength(int l) - { - assert(length >= 0); // able to accept a length - assert((int)l >= 0); // no overflow - assert(rplimit == nullptr); // readData not yet called - length += l; - assert(length >= l); // no overflow - } - - void setIndex(cpindex *ix_); - void setIndexByTag(byte tag); - - // Parse the band and its meta-coding header. - void readData(int expectedLength = 0); - - // Reset the band for another pass (Cf. Java Band.resetForSecondPass.) - void rewind() - { - cm.reset(&vs[0]); - } - - byte *&curRP() - { - return vs[0].rp; - } - byte *minRP() - { - return cm.vs0.rp; - } - byte *maxRP() - { - return rplimit; - } - size_t size() - { - return maxRP() - minRP(); - } - - int getByte() - { - assert(ix == nullptr); - return vs[0].getByte(); - } - int getInt() - { - assert(ix == nullptr); - return vs[0].getInt(); - } - entry *getRefN() - { - assert(ix != nullptr); - return getRefCommon(ix, true); - } - entry *getRef() - { - assert(ix != nullptr); - return getRefCommon(ix, false); - } - entry *getRefUsing(cpindex *ix2) - { - assert(ix == nullptr); - return getRefCommon(ix2, true); - } - entry *getRefCommon(cpindex *ix, bool nullOK); - int64_t getLong(band &lo_band, bool have_hi); - - static int64_t makeLong(uint32_t hi, uint32_t lo) - { - return ((uint64_t)hi << 32) + (((uint64_t)lo << 32) >> 32); - } - - int getIntTotal(); - int getIntCount(int tag); - - static band *makeBands(unpacker *u); - static void initIndexes(unpacker *u); -}; - -extern band all_bands[]; - -#define BAND_LOCAL /* \ - band* band_temp = all_bands; \ - band* all_bands = band_temp */ - -// Band schema: -enum band_number -{ - // e_archive_magic, - // e_archive_header, - // e_band_headers, - - // constant pool contents - e_cp_Utf8_prefix, - e_cp_Utf8_suffix, - e_cp_Utf8_chars, - e_cp_Utf8_big_suffix, - e_cp_Utf8_big_chars, - e_cp_Int, - e_cp_Float, - e_cp_Long_hi, - e_cp_Long_lo, - e_cp_Double_hi, - e_cp_Double_lo, - e_cp_String, - e_cp_Class, - e_cp_Signature_form, - e_cp_Signature_classes, - e_cp_Descr_name, - e_cp_Descr_type, - e_cp_Field_class, - e_cp_Field_desc, - e_cp_Method_class, - e_cp_Method_desc, - e_cp_Imethod_class, - e_cp_Imethod_desc, - - // bands which define transmission of attributes - e_attr_definition_headers, - e_attr_definition_name, - e_attr_definition_layout, - - // band for hardwired InnerClasses attribute (shared across the package) - e_ic_this_class, - e_ic_flags, - // These bands contain data only where flags sets ACC_IC_LONG_FORM: - e_ic_outer_class, - e_ic_name, - - // bands for carrying class schema information: - e_class_this, - e_class_super, - e_class_interface_count, - e_class_interface, - - // bands for class members - e_class_field_count, - e_class_method_count, - e_field_descr, - e_field_flags_hi, - e_field_flags_lo, - e_field_attr_count, - e_field_attr_indexes, - e_field_attr_calls, - e_field_ConstantValue_KQ, - e_field_Signature_RS, - e_field_metadata_bands, - e_field_attr_bands, - e_method_descr, - e_method_flags_hi, - e_method_flags_lo, - e_method_attr_count, - e_method_attr_indexes, - e_method_attr_calls, - e_method_Exceptions_N, - e_method_Exceptions_RC, - e_method_Signature_RS, - e_method_metadata_bands, - e_method_attr_bands, - e_class_flags_hi, - e_class_flags_lo, - e_class_attr_count, - e_class_attr_indexes, - e_class_attr_calls, - e_class_SourceFile_RUN, - e_class_EnclosingMethod_RC, - e_class_EnclosingMethod_RDN, - e_class_Signature_RS, - e_class_metadata_bands, - e_class_InnerClasses_N, - e_class_InnerClasses_RC, - e_class_InnerClasses_F, - e_class_InnerClasses_outer_RCN, - e_class_InnerClasses_name_RUN, - e_class_ClassFile_version_minor_H, - e_class_ClassFile_version_major_H, - e_class_attr_bands, - e_code_headers, - e_code_max_stack, - e_code_max_na_locals, - e_code_handler_count, - e_code_handler_start_P, - e_code_handler_end_PO, - e_code_handler_catch_PO, - e_code_handler_class_RCN, - - // code attributes - e_code_flags_hi, - e_code_flags_lo, - e_code_attr_count, - e_code_attr_indexes, - e_code_attr_calls, - e_code_StackMapTable_N, - e_code_StackMapTable_frame_T, - e_code_StackMapTable_local_N, - e_code_StackMapTable_stack_N, - e_code_StackMapTable_offset, - e_code_StackMapTable_T, - e_code_StackMapTable_RC, - e_code_StackMapTable_P, - e_code_LineNumberTable_N, - e_code_LineNumberTable_bci_P, - e_code_LineNumberTable_line, - e_code_LocalVariableTable_N, - e_code_LocalVariableTable_bci_P, - e_code_LocalVariableTable_span_O, - e_code_LocalVariableTable_name_RU, - e_code_LocalVariableTable_type_RS, - e_code_LocalVariableTable_slot, - e_code_LocalVariableTypeTable_N, - e_code_LocalVariableTypeTable_bci_P, - e_code_LocalVariableTypeTable_span_O, - e_code_LocalVariableTypeTable_name_RU, - e_code_LocalVariableTypeTable_type_RS, - e_code_LocalVariableTypeTable_slot, - e_code_attr_bands, - - // bands for bytecodes - e_bc_codes, - // remaining bands provide typed opcode fields required by the bc_codes - e_bc_case_count, - e_bc_case_value, - e_bc_byte, - e_bc_short, - e_bc_local, - e_bc_label, - - // ldc* operands: - e_bc_intref, - e_bc_floatref, - e_bc_longref, - e_bc_doubleref, - e_bc_stringref, - e_bc_classref, - e_bc_fieldref, - e_bc_methodref, - e_bc_imethodref, - - // _self_linker_op family - e_bc_thisfield, - e_bc_superfield, - e_bc_thismethod, - e_bc_supermethod, - - // bc_invokeinit family: - e_bc_initref, - - // bytecode escape sequences - e_bc_escref, - e_bc_escrefsize, - e_bc_escsize, - e_bc_escbyte, - - // file attributes and contents - e_file_name, - e_file_size_hi, - e_file_size_lo, - e_file_modtime, - e_file_options, - // e_file_bits, // handled specially as an appendix - BAND_LIMIT -}; - -// Symbolic names for bands, as if in a giant global struct: -//#define archive_magic all_bands[e_archive_magic] -//#define archive_header all_bands[e_archive_header] -//#define band_headers all_bands[e_band_headers] -#define cp_Utf8_prefix all_bands[e_cp_Utf8_prefix] -#define cp_Utf8_suffix all_bands[e_cp_Utf8_suffix] -#define cp_Utf8_chars all_bands[e_cp_Utf8_chars] -#define cp_Utf8_big_suffix all_bands[e_cp_Utf8_big_suffix] -#define cp_Utf8_big_chars all_bands[e_cp_Utf8_big_chars] -#define cp_Int all_bands[e_cp_Int] -#define cp_Float all_bands[e_cp_Float] -#define cp_Long_hi all_bands[e_cp_Long_hi] -#define cp_Long_lo all_bands[e_cp_Long_lo] -#define cp_Double_hi all_bands[e_cp_Double_hi] -#define cp_Double_lo all_bands[e_cp_Double_lo] -#define cp_String all_bands[e_cp_String] -#define cp_Class all_bands[e_cp_Class] -#define cp_Signature_form all_bands[e_cp_Signature_form] -#define cp_Signature_classes all_bands[e_cp_Signature_classes] -#define cp_Descr_name all_bands[e_cp_Descr_name] -#define cp_Descr_type all_bands[e_cp_Descr_type] -#define cp_Field_class all_bands[e_cp_Field_class] -#define cp_Field_desc all_bands[e_cp_Field_desc] -#define cp_Method_class all_bands[e_cp_Method_class] -#define cp_Method_desc all_bands[e_cp_Method_desc] -#define cp_Imethod_class all_bands[e_cp_Imethod_class] -#define cp_Imethod_desc all_bands[e_cp_Imethod_desc] -#define attr_definition_headers all_bands[e_attr_definition_headers] -#define attr_definition_name all_bands[e_attr_definition_name] -#define attr_definition_layout all_bands[e_attr_definition_layout] -#define ic_this_class all_bands[e_ic_this_class] -#define ic_flags all_bands[e_ic_flags] -#define ic_outer_class all_bands[e_ic_outer_class] -#define ic_name all_bands[e_ic_name] -#define class_this all_bands[e_class_this] -#define class_super all_bands[e_class_super] -#define class_interface_count all_bands[e_class_interface_count] -#define class_interface all_bands[e_class_interface] -#define class_field_count all_bands[e_class_field_count] -#define class_method_count all_bands[e_class_method_count] -#define field_descr all_bands[e_field_descr] -#define field_flags_hi all_bands[e_field_flags_hi] -#define field_flags_lo all_bands[e_field_flags_lo] -#define field_attr_count all_bands[e_field_attr_count] -#define field_attr_indexes all_bands[e_field_attr_indexes] -#define field_ConstantValue_KQ all_bands[e_field_ConstantValue_KQ] -#define field_Signature_RS all_bands[e_field_Signature_RS] -#define field_attr_bands all_bands[e_field_attr_bands] -#define method_descr all_bands[e_method_descr] -#define method_flags_hi all_bands[e_method_flags_hi] -#define method_flags_lo all_bands[e_method_flags_lo] -#define method_attr_count all_bands[e_method_attr_count] -#define method_attr_indexes all_bands[e_method_attr_indexes] -#define method_Exceptions_N all_bands[e_method_Exceptions_N] -#define method_Exceptions_RC all_bands[e_method_Exceptions_RC] -#define method_Signature_RS all_bands[e_method_Signature_RS] -#define method_attr_bands all_bands[e_method_attr_bands] -#define class_flags_hi all_bands[e_class_flags_hi] -#define class_flags_lo all_bands[e_class_flags_lo] -#define class_attr_count all_bands[e_class_attr_count] -#define class_attr_indexes all_bands[e_class_attr_indexes] -#define class_SourceFile_RUN all_bands[e_class_SourceFile_RUN] -#define class_EnclosingMethod_RC all_bands[e_class_EnclosingMethod_RC] -#define class_EnclosingMethod_RDN all_bands[e_class_EnclosingMethod_RDN] -#define class_Signature_RS all_bands[e_class_Signature_RS] -#define class_InnerClasses_N all_bands[e_class_InnerClasses_N] -#define class_InnerClasses_RC all_bands[e_class_InnerClasses_RC] -#define class_InnerClasses_F all_bands[e_class_InnerClasses_F] -#define class_InnerClasses_outer_RCN all_bands[e_class_InnerClasses_outer_RCN] -#define class_InnerClasses_name_RUN all_bands[e_class_InnerClasses_name_RUN] -#define class_ClassFile_version_minor_H all_bands[e_class_ClassFile_version_minor_H] -#define class_ClassFile_version_major_H all_bands[e_class_ClassFile_version_major_H] -#define class_attr_bands all_bands[e_class_attr_bands] -#define code_headers all_bands[e_code_headers] -#define code_max_stack all_bands[e_code_max_stack] -#define code_max_na_locals all_bands[e_code_max_na_locals] -#define code_handler_count all_bands[e_code_handler_count] -#define code_handler_start_P all_bands[e_code_handler_start_P] -#define code_handler_end_PO all_bands[e_code_handler_end_PO] -#define code_handler_catch_PO all_bands[e_code_handler_catch_PO] -#define code_handler_class_RCN all_bands[e_code_handler_class_RCN] -#define code_flags_hi all_bands[e_code_flags_hi] -#define code_flags_lo all_bands[e_code_flags_lo] -#define code_attr_count all_bands[e_code_attr_count] -#define code_attr_indexes all_bands[e_code_attr_indexes] -#define code_StackMapTable_N all_bands[e_code_StackMapTable_N] -#define code_StackMapTable_frame_T all_bands[e_code_StackMapTable_frame_T] -#define code_StackMapTable_local_N all_bands[e_code_StackMapTable_local_N] -#define code_StackMapTable_stack_N all_bands[e_code_StackMapTable_stack_N] -#define code_StackMapTable_offset all_bands[e_code_StackMapTable_offset] -#define code_StackMapTable_T all_bands[e_code_StackMapTable_T] -#define code_StackMapTable_RC all_bands[e_code_StackMapTable_RC] -#define code_StackMapTable_P all_bands[e_code_StackMapTable_P] -#define code_LineNumberTable_N all_bands[e_code_LineNumberTable_N] -#define code_LineNumberTable_bci_P all_bands[e_code_LineNumberTable_bci_P] -#define code_LineNumberTable_line all_bands[e_code_LineNumberTable_line] -#define code_LocalVariableTable_N all_bands[e_code_LocalVariableTable_N] -#define code_LocalVariableTable_bci_P all_bands[e_code_LocalVariableTable_bci_P] -#define code_LocalVariableTable_span_O all_bands[e_code_LocalVariableTable_span_O] -#define code_LocalVariableTable_name_RU all_bands[e_code_LocalVariableTable_name_RU] -#define code_LocalVariableTable_type_RS all_bands[e_code_LocalVariableTable_type_RS] -#define code_LocalVariableTable_slot all_bands[e_code_LocalVariableTable_slot] -#define code_LocalVariableTypeTable_N all_bands[e_code_LocalVariableTypeTable_N] -#define code_LocalVariableTypeTable_bci_P all_bands[e_code_LocalVariableTypeTable_bci_P] -#define code_LocalVariableTypeTable_span_O all_bands[e_code_LocalVariableTypeTable_span_O] -#define code_LocalVariableTypeTable_name_RU all_bands[e_code_LocalVariableTypeTable_name_RU] -#define code_LocalVariableTypeTable_type_RS all_bands[e_code_LocalVariableTypeTable_type_RS] -#define code_LocalVariableTypeTable_slot all_bands[e_code_LocalVariableTypeTable_slot] -#define code_attr_bands all_bands[e_code_attr_bands] -#define bc_codes all_bands[e_bc_codes] -#define bc_case_count all_bands[e_bc_case_count] -#define bc_case_value all_bands[e_bc_case_value] -#define bc_byte all_bands[e_bc_byte] -#define bc_short all_bands[e_bc_short] -#define bc_local all_bands[e_bc_local] -#define bc_label all_bands[e_bc_label] -#define bc_intref all_bands[e_bc_intref] -#define bc_floatref all_bands[e_bc_floatref] -#define bc_longref all_bands[e_bc_longref] -#define bc_doubleref all_bands[e_bc_doubleref] -#define bc_stringref all_bands[e_bc_stringref] -#define bc_classref all_bands[e_bc_classref] -#define bc_fieldref all_bands[e_bc_fieldref] -#define bc_methodref all_bands[e_bc_methodref] -#define bc_imethodref all_bands[e_bc_imethodref] -#define bc_thisfield all_bands[e_bc_thisfield] -#define bc_superfield all_bands[e_bc_superfield] -#define bc_thismethod all_bands[e_bc_thismethod] -#define bc_supermethod all_bands[e_bc_supermethod] -#define bc_initref all_bands[e_bc_initref] -#define bc_escref all_bands[e_bc_escref] -#define bc_escrefsize all_bands[e_bc_escrefsize] -#define bc_escsize all_bands[e_bc_escsize] -#define bc_escbyte all_bands[e_bc_escbyte] -#define file_name all_bands[e_file_name] -#define file_size_hi all_bands[e_file_size_hi] -#define file_size_lo all_bands[e_file_size_lo] -#define file_modtime all_bands[e_file_modtime] -#define file_options all_bands[e_file_options] diff --git a/libraries/pack200/src/bytes.cpp b/libraries/pack200/src/bytes.cpp deleted file mode 100644 index 767fe0a5..00000000 --- a/libraries/pack200/src/bytes.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include -#include -#include -#include "defines.h" -#include "bytes.h" -#include "utils.h" - -static byte dummy[1 << 10]; - -bool bytes::inBounds(const void *p) -{ - return p >= ptr && p < limit(); -} - -void bytes::malloc(size_t len_) -{ - len = len_; - ptr = NEW(byte, add_size(len_, 1)); // add trailing zero byte always - if (ptr == nullptr) - { - // set ptr to some victim memory, to ease escape - set(dummy, sizeof(dummy) - 1); - unpack_abort(ERROR_ENOMEM); - } -} - -void bytes::realloc(size_t len_) -{ - if (len == len_) - return; // nothing to do - if (ptr == dummy) - return; // escaping from an error - if (ptr == nullptr) - { - malloc(len_); - return; - } - byte *oldptr = ptr; - ptr = (len_ >= PSIZE_MAX) ? nullptr : (byte *)::realloc(ptr, add_size(len_, 1)); - if (ptr != nullptr) - { - if (len < len_) - memset(ptr + len, 0, len_ - len); - ptr[len_] = 0; - len = len_; - } - else - { - ptr = oldptr; // ease our escape - unpack_abort(ERROR_ENOMEM); - } -} - -void bytes::free() -{ - if (ptr == dummy) - return; // escaping from an error - if (ptr != nullptr) - { - ::free(ptr); - } - len = 0; - ptr = 0; -} - -int bytes::indexOf(byte c) -{ - byte *p = (byte *)memchr(ptr, c, len); - return (p == 0) ? -1 : (int)(p - ptr); -} - -byte *bytes::writeTo(byte *bp) -{ - memcpy(bp, ptr, len); - return bp + len; -} - -int bytes::compareTo(bytes &other) -{ - size_t l1 = len; - size_t l2 = other.len; - int cmp = memcmp(ptr, other.ptr, (l1 < l2) ? l1 : l2); - if (cmp != 0) - return cmp; - return (l1 < l2) ? -1 : (l1 > l2) ? 1 : 0; -} - -void bytes::saveFrom(const void *ptr_, size_t len_) -{ - malloc(len_); - // Save as much as possible. - if (len_ > len) - { - assert(ptr == dummy); // error recovery - len_ = len; - } - copyFrom(ptr_, len_); -} - -//#TODO: Need to fix for exception handling -void bytes::copyFrom(const void *ptr_, size_t len_, size_t offset) -{ - assert(len_ == 0 || inBounds(ptr + offset)); - assert(len_ == 0 || inBounds(ptr + offset + len_ - 1)); - memcpy(ptr + offset, ptr_, len_); -} - -// Make sure there are 'o' bytes beyond the fill pointer, -// advance the fill pointer, and return the old fill pointer. -byte *fillbytes::grow(size_t s) -{ - size_t nlen = add_size(b.len, s); - if (nlen <= allocated) - { - b.len = nlen; - return limit() - s; - } - size_t maxlen = nlen; - if (maxlen < 128) - maxlen = 128; - if (maxlen < allocated * 2) - maxlen = allocated * 2; - if (allocated == 0) - { - // Initial buffer was not malloced. Do not reallocate it. - bytes old = b; - b.malloc(maxlen); - if (b.len == maxlen) - old.writeTo(b.ptr); - } - else - { - b.realloc(maxlen); - } - allocated = b.len; - if (allocated != maxlen) - { - b.len = nlen - s; // back up - return dummy; // scribble during error recov. - } - // after realloc, recompute pointers - b.len = nlen; - assert(b.len <= allocated); - return limit() - s; -} - -void fillbytes::ensureSize(size_t s) -{ - if (allocated >= s) - return; - size_t len0 = b.len; - grow(s - size()); - b.len = len0; // put it back -} - -int ptrlist::indexOf(const void *x) -{ - int len = length(); - for (int i = 0; i < len; i++) - { - if (get(i) == x) - return i; - } - return -1; -} - -void ptrlist::freeAll() -{ - int len = length(); - for (int i = 0; i < len; i++) - { - void *p = (void *)get(i); - if (p != nullptr) - { - ::free(p); - } - } - free(); -} - -int intlist::indexOf(int x) -{ - int len = length(); - for (int i = 0; i < len; i++) - { - if (get(i) == x) - return i; - } - return -1; -} diff --git a/libraries/pack200/src/bytes.h b/libraries/pack200/src/bytes.h deleted file mode 100644 index 2ce1f7f4..00000000 --- a/libraries/pack200/src/bytes.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#pragma once - -struct bytes -{ - int8_t *ptr; - size_t len; - int8_t *limit() - { - return ptr + len; - } - - void set(int8_t *ptr_, size_t len_) - { - ptr = ptr_; - len = len_; - } - void set(const char *str) - { - ptr = (int8_t *)str; - len = strlen(str); - } - bool inBounds(const void *p); // p in [ptr, limit) - void malloc(size_t len_); - void realloc(size_t len_); - void free(); - void copyFrom(const void *ptr_, size_t len_, size_t offset = 0); - void saveFrom(const void *ptr_, size_t len_); - void saveFrom(const char *str) - { - saveFrom(str, strlen(str)); - } - void copyFrom(bytes &other, size_t offset = 0) - { - copyFrom(other.ptr, other.len, offset); - } - void saveFrom(bytes &other) - { - saveFrom(other.ptr, other.len); - } - void clear(int fill_byte = 0) - { - memset(ptr, fill_byte, len); - } - int8_t *writeTo(int8_t *bp); - bool equals(bytes &other) - { - return 0 == compareTo(other); - } - int compareTo(bytes &other); - bool contains(int8_t c) - { - return indexOf(c) >= 0; - } - int indexOf(int8_t c); - // substrings: - static bytes of(int8_t *ptr, size_t len) - { - bytes res; - res.set(ptr, len); - return res; - } - bytes slice(size_t beg, size_t end) - { - bytes res; - res.ptr = ptr + beg; - res.len = end - beg; - assert(res.len == 0 ||(inBounds(res.ptr) && inBounds(res.limit() - 1))); - return res; - } - // building C strings inside byte buffers: - bytes &strcat(const char *str) - { - ::strcat((char *)ptr, str); - return *this; - } - bytes &strcat(bytes &other) - { - ::strncat((char *)ptr, (char *)other.ptr, other.len); - return *this; - } - char *strval() - { - assert(strlen((char *)ptr) == len); - return (char *)ptr; - } -}; -#define BYTES_OF(var) (bytes::of((int8_t *)&(var), sizeof(var))) - -struct fillbytes -{ - bytes b; - size_t allocated; - - int8_t *base() - { - return b.ptr; - } - size_t size() - { - return b.len; - } - int8_t *limit() - { - return b.limit(); - } // logical limit - void setLimit(int8_t *lp) - { - assert(isAllocated(lp)); - b.len = lp - b.ptr; - } - int8_t *end() - { - return b.ptr + allocated; - } // physical limit - int8_t *loc(size_t o) - { - assert(o < b.len); - return b.ptr + o; - } - void init() - { - allocated = 0; - b.set(nullptr, 0); - } - void init(size_t s) - { - init(); - ensureSize(s); - } - void free() - { - if (allocated != 0) - b.free(); - allocated = 0; - } - void empty() - { - b.len = 0; - } - int8_t *grow(size_t s); // grow so that limit() += s - int getByte(uint32_t i) - { - return *loc(i) & 0xFF; - } - void addByte(int8_t x) - { - *grow(1) = x; - } - void ensureSize(size_t s); // make sure allocated >= s - void trimToSize() - { - if (allocated > size()) - b.realloc(allocated = size()); - } - bool canAppend(size_t s) - { - return allocated > b.len + s; - } - bool isAllocated(int8_t *p) - { - return p >= base() && p <= end(); - } // asserts - void set(bytes &src) - { - set(src.ptr, src.len); - } - - void set(int8_t *ptr, size_t len) - { - b.set(ptr, len); - allocated = 0; // mark as not reallocatable - } - - // block operations on resizing byte buffer: - fillbytes &append(const void *ptr_, size_t len_) - { - memcpy(grow(len_), ptr_, len_); - return (*this); - } - fillbytes &append(bytes &other) - { - return append(other.ptr, other.len); - } - fillbytes &append(const char *str) - { - return append(str, strlen(str)); - } -}; - -struct ptrlist : fillbytes -{ - typedef const void *cvptr; - int length() - { - return (int)(size() / sizeof(cvptr)); - } - cvptr *base() - { - return (cvptr *)fillbytes::base(); - } - cvptr &get(int i) - { - return *(cvptr *)loc(i * sizeof(cvptr)); - } - cvptr *limit() - { - return (cvptr *)fillbytes::limit(); - } - void add(cvptr x) - { - *(cvptr *)grow(sizeof(x)) = x; - } - void popTo(int l) - { - assert(l <= length()); - b.len = l * sizeof(cvptr); - } - int indexOf(cvptr x); - bool contains(cvptr x) - { - return indexOf(x) >= 0; - } - void freeAll(); // frees every ptr on the list, plus the list itself -}; -// Use a macro rather than mess with subtle mismatches -// between member and non-member function pointers. -#define PTRLIST_QSORT(ptrls, fn) ::qsort((ptrls).base(), (ptrls).length(), sizeof(void *), fn) - -struct intlist : fillbytes -{ - int length() - { - return (int)(size() / sizeof(int)); - } - int *base() - { - return (int *)fillbytes::base(); - } - int &get(int i) - { - return *(int *)loc(i * sizeof(int)); - } - int *limit() - { - return (int *)fillbytes::limit(); - } - void add(int x) - { - *(int *)grow(sizeof(x)) = x; - } - void popTo(int l) - { - assert(l <= length()); - b.len = l * sizeof(int); - } - int indexOf(int x); - bool contains(int x) - { - return indexOf(x) >= 0; - } -}; diff --git a/libraries/pack200/src/coding.cpp b/libraries/pack200/src/coding.cpp deleted file mode 100644 index 8e872013..00000000 --- a/libraries/pack200/src/coding.cpp +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// -*- C++ -*- -// Small program for unpacking specially compressed Java packages. -// John R. Rose - -#include -#include -#include -#include -#include -#include - -#include "defines.h" -#include "bytes.h" -#include "utils.h" -#include "coding.h" - -#include "constants.h" -#include "unpack.h" - -extern coding basic_codings[]; - -// CODING_PRIVATE causes a lot of them -#pragma GCC diagnostic ignored "-Wunused-variable" - -#define CODING_PRIVATE(spec) \ - int spec_ = spec; \ - int B = CODING_B(spec_); \ - int H = CODING_H(spec_); \ - int L = 256 - H; \ - int S = CODING_S(spec_); \ - int D = CODING_D(spec_) - -#define IS_NEG_CODE(S, codeVal) ((((int)(codeVal) + 1) & ((1 << S) - 1)) == 0) - -#define DECODE_SIGN_S1(ux) (((uint32_t)(ux) >> 1) ^ -((int)(ux) & 1)) - -static int decode_sign(int S, uint32_t ux) -{ // == Coding.decodeSign32 - assert(S > 0); - uint32_t sigbits = (ux >> S); - if (IS_NEG_CODE(S, ux)) - return (int)(~sigbits); - else - return (int)(ux - sigbits); - // Note that (int)(ux-sigbits) can be negative, if ux is large enough. -} - -coding *coding::init() -{ - if (umax > 0) - return this; // already done - assert(spec != 0); // sanity - - // fill in derived fields - CODING_PRIVATE(spec); - - // Return nullptr if 'arb(BHSD)' parameter constraints are not met: - if (B < 1 || B > B_MAX) - return nullptr; - if (H < 1 || H > 256) - return nullptr; - if (S < 0 || S > 2) - return nullptr; - if (D < 0 || D > 1) - return nullptr; - if (B == 1 && H != 256) - return nullptr; // 1-byte coding must be fixed-size - if (B >= 5 && H == 256) - return nullptr; // no 5-byte fixed-size coding - - // first compute the range of the coding, in 64 bits - int64_t range = 0; - { - int64_t H_i = 1; - for (int i = 0; i < B; i++) - { - range += H_i; - H_i *= H; - } - range *= L; - range += H_i; - } - assert(range > 0); // no useless codings, please - - int this_umax; - - // now, compute min and max - if (range >= ((int64_t)1 << 32)) - { - this_umax = INT_MAX_VALUE; - this->umin = INT_MIN_VALUE; - this->max = INT_MAX_VALUE; - this->min = INT_MIN_VALUE; - } - else - { - this_umax = (range > INT_MAX_VALUE) ? INT_MAX_VALUE : (int)range - 1; - this->max = this_umax; - this->min = this->umin = 0; - if (S != 0 && range != 0) - { - int64_t maxPosCode = range - 1; - int64_t maxNegCode = range - 1; - while (IS_NEG_CODE(S, maxPosCode)) - --maxPosCode; - while (!IS_NEG_CODE(S, maxNegCode)) - --maxNegCode; - int maxPos = decode_sign(S, (uint32_t)maxPosCode); - if (maxPos < 0) - this->max = INT_MAX_VALUE; // 32-bit wraparound - else - this->max = maxPos; - if (maxNegCode < 0) - this->min = 0; // No negative codings at all. - else - this->min = decode_sign(S, (uint32_t)maxNegCode); - } - } - - assert(!(isFullRange | isSigned | isSubrange)); // init - if (min < 0) - this->isSigned = true; - if (max < INT_MAX_VALUE && range <= INT_MAX_VALUE) - this->isSubrange = true; - if (max == INT_MAX_VALUE && min == INT_MIN_VALUE) - this->isFullRange = true; - - // do this last, to reduce MT exposure (should have a membar too) - this->umax = this_umax; - - return this; -} - -coding *coding::findBySpec(int spec) -{ - for (coding *scan = &basic_codings[0];; scan++) - { - if (scan->spec == spec) - return scan->init(); - if (scan->spec == 0) - break; - } - coding *ptr = NEW(coding, 1); - if (!ptr) - return nullptr; - coding *c = ptr->initFrom(spec); - if (c == nullptr) - { - ::free(ptr); - } - else - // else caller should free it... - c->isMalloc = true; - return c; -} - -coding *coding::findBySpec(int B, int H, int S, int D) -{ - if (B < 1 || B > B_MAX) - return nullptr; - if (H < 1 || H > 256) - return nullptr; - if (S < 0 || S > 2) - return nullptr; - if (D < 0 || D > 1) - return nullptr; - return findBySpec(CODING_SPEC(B, H, S, D)); -} - -void coding::free() -{ - if (isMalloc) - { - ::free(this); - } -} - -void coding_method::reset(value_stream *state) -{ - assert(state->rp == state->rplimit); // not in mid-stream, please - // assert(this == vs0.cm); - state[0] = vs0; - if (uValues != nullptr) - { - uValues->reset(state->helper()); - } -} - -uint32_t coding::parse(byte *&rp, int B, int H) -{ - int L = 256 - H; - byte *ptr = rp; - // hand peel the i==0 part of the loop: - uint32_t b_i = *ptr++ & 0xFF; - if (B == 1 || b_i < (uint32_t)L) - { - rp = ptr; - return b_i; - } - uint32_t sum = b_i; - uint32_t H_i = H; - assert(B <= B_MAX); - for (int i = 2; i <= B_MAX; i++) - { // easy for compilers to unroll if desired - b_i = *ptr++ & 0xFF; - sum += b_i * H_i; - if (i == B || b_i < (uint32_t)L) - { - rp = ptr; - return sum; - } - H_i *= H; - } - assert(false); - return 0; -} - -uint32_t coding::parse_lgH(byte *&rp, int B, int H, int lgH) -{ - assert(H == (1 << lgH)); - int L = 256 - (1 << lgH); - byte *ptr = rp; - // hand peel the i==0 part of the loop: - uint32_t b_i = *ptr++ & 0xFF; - if (B == 1 || b_i < (uint32_t)L) - { - rp = ptr; - return b_i; - } - uint32_t sum = b_i; - uint32_t lg_H_i = lgH; - assert(B <= B_MAX); - for (int i = 2; i <= B_MAX; i++) - { // easy for compilers to unroll if desired - b_i = *ptr++ & 0xFF; - sum += b_i << lg_H_i; - if (i == B || b_i < (uint32_t)L) - { - rp = ptr; - return sum; - } - lg_H_i += lgH; - } - assert(false); - return 0; -} - -static const char ERB[] = "EOF reading band"; - -void coding::parseMultiple(byte *&rp, int N, byte *limit, int B, int H) -{ - if (N < 0) - { - unpack_abort("bad value count"); - return; - } - byte *ptr = rp; - if (B == 1 || H == 256) - { - size_t len = (size_t)N * B; - if (len / B != (size_t)N || ptr + len > limit) - { - unpack_abort(ERB); - return; - } - rp = ptr + len; - return; - } - // Note: We assume rp has enough zero-padding. - int L = 256 - H; - int n = B; - while (N > 0) - { - ptr += 1; - if (--n == 0) - { - // end of encoding at B bytes, regardless of byte value - } - else - { - int b = (ptr[-1] & 0xFF); - if (b >= L) - { - // keep going, unless we find a byte < L - continue; - } - } - // found the last byte - N -= 1; - n = B; // reset length counter - // do an error check here - if (ptr > limit) - { - unpack_abort(ERB); - return; - } - } - rp = ptr; - return; -} - -bool value_stream::hasHelper() -{ - // If my coding method is a pop-style method, - // then I need a second value stream to transmit - // unfavored values. - // This can be determined by examining fValues. - return cm->fValues != nullptr; -} - -void value_stream::init(byte *rp_, byte *rplimit_, coding *defc) -{ - rp = rp_; - rplimit = rplimit_; - sum = 0; - cm = nullptr; // no need in the simple case - setCoding(defc); -} - -void value_stream::setCoding(coding *defc) -{ - if (defc == nullptr) - { - unpack_abort("bad coding"); - defc = coding::findByIndex(_meta_canon_min); // random pick for recovery - } - - c = (*defc); - - // choose cmk - cmk = cmk_ERROR; - switch (c.spec) - { - case BYTE1_spec: - cmk = cmk_BYTE1; - break; - case CHAR3_spec: - cmk = cmk_CHAR3; - break; - case UNSIGNED5_spec: - cmk = cmk_UNSIGNED5; - break; - case DELTA5_spec: - cmk = cmk_DELTA5; - break; - case BCI5_spec: - cmk = cmk_BCI5; - break; - case BRANCH5_spec: - cmk = cmk_BRANCH5; - break; - default: - if (c.D() == 0) - { - switch (c.S()) - { - case 0: - cmk = cmk_BHS0; - break; - case 1: - cmk = cmk_BHS1; - break; - default: - cmk = cmk_BHS; - break; - } - } - else - { - if (c.S() == 1) - { - if (c.isFullRange) - cmk = cmk_BHS1D1full; - if (c.isSubrange) - cmk = cmk_BHS1D1sub; - } - if (cmk == cmk_ERROR) - cmk = cmk_BHSD1; - } - } -} - -static int getPopValue(value_stream *self, uint32_t uval) -{ - if (uval > 0) - { - // note that the initial parse performed a range check - assert(uval <= (uint32_t)self->cm->fVlength); - return self->cm->fValues[uval - 1]; - } - else - { - // take an unfavored value - return self->helper()->getInt(); - } -} - -int coding::sumInUnsignedRange(int x, int y) -{ - assert(isSubrange); - int range = (int)(umax + 1); - assert(range > 0); - x += y; - if (x != (int)((int64_t)(x - y) + (int64_t)y)) - { - // 32-bit overflow interferes with range reduction. - // Back off from the overflow by adding a multiple of range: - if (x < 0) - { - x -= range; - assert(x >= 0); - } - else - { - x += range; - assert(x < 0); - } - } - if (x < 0) - { - x += range; - if (x >= 0) - return x; - } - else if (x >= range) - { - x -= range; - if (x < range) - return x; - } - else - { - // in range - return x; - } - // do it the hard way - x %= range; - if (x < 0) - x += range; - return x; -} - -static int getDeltaValue(value_stream *self, uint32_t uval, bool isSubrange) -{ - assert((uint32_t)(self->c.isSubrange) == (uint32_t)isSubrange); - assert(self->c.isSubrange | self->c.isFullRange); - if (isSubrange) - return self->sum = self->c.sumInUnsignedRange(self->sum, (int)uval); - else - return self->sum += (int)uval; -} - -bool value_stream::hasValue() -{ - if (rp < rplimit) - return true; - if (cm == nullptr) - return false; - if (cm->next == nullptr) - return false; - cm->next->reset(this); - return hasValue(); -} - -int value_stream::getInt() -{ - if (rp >= rplimit) - { - // Advance to next coding segment. - if (rp > rplimit || cm == nullptr || cm->next == nullptr) - { - // Must perform this check and throw an exception on bad input. - unpack_abort(ERB); - return 0; - } - cm->next->reset(this); - return getInt(); - } - - CODING_PRIVATE(c.spec); - uint32_t uval; - enum - { - B5 = 5, - B3 = 3, - H128 = 128, - H64 = 64, - H4 = 4 - }; - switch (cmk) - { - case cmk_BHS: - assert(D == 0); - uval = coding::parse(rp, B, H); - if (S == 0) - return (int)uval; - return decode_sign(S, uval); - - case cmk_BHS0: - assert(S == 0 && D == 0); - uval = coding::parse(rp, B, H); - return (int)uval; - - case cmk_BHS1: - assert(S == 1 && D == 0); - uval = coding::parse(rp, B, H); - return DECODE_SIGN_S1(uval); - - case cmk_BYTE1: - assert(c.spec == BYTE1_spec); - assert(B == 1 && H == 256 && S == 0 && D == 0); - return *rp++ & 0xFF; - - case cmk_CHAR3: - assert(c.spec == CHAR3_spec); - assert(B == B3 && H == H128 && S == 0 && D == 0); - return coding::parse_lgH(rp, B3, H128, 7); - - case cmk_UNSIGNED5: - assert(c.spec == UNSIGNED5_spec); - assert(B == B5 && H == H64 && S == 0 && D == 0); - return coding::parse_lgH(rp, B5, H64, 6); - - case cmk_BHSD1: - assert(D == 1); - uval = coding::parse(rp, B, H); - if (S != 0) - uval = (uint32_t)decode_sign(S, uval); - return getDeltaValue(this, uval, (bool)c.isSubrange); - - case cmk_BHS1D1full: - assert(S == 1 && D == 1 && c.isFullRange); - uval = coding::parse(rp, B, H); - uval = (uint32_t)DECODE_SIGN_S1(uval); - return getDeltaValue(this, uval, false); - - case cmk_BHS1D1sub: - assert(S == 1 && D == 1 && c.isSubrange); - uval = coding::parse(rp, B, H); - uval = (uint32_t)DECODE_SIGN_S1(uval); - return getDeltaValue(this, uval, true); - - case cmk_DELTA5: - assert(c.spec == DELTA5_spec); - assert(B == B5 && H == H64 && S == 1 && D == 1 && c.isFullRange); - uval = coding::parse_lgH(rp, B5, H64, 6); - sum += DECODE_SIGN_S1(uval); - return sum; - - case cmk_BCI5: - assert(c.spec == BCI5_spec); - assert(B == B5 && H == H4 && S == 0 && D == 0); - return coding::parse_lgH(rp, B5, H4, 2); - - case cmk_BRANCH5: - assert(c.spec == BRANCH5_spec); - assert(B == B5 && H == H4 && S == 2 && D == 0); - uval = coding::parse_lgH(rp, B5, H4, 2); - return decode_sign(S, uval); - - case cmk_pop: - uval = coding::parse(rp, B, H); - if (S != 0) - { - uval = (uint32_t)decode_sign(S, uval); - } - if (D != 0) - { - assert(c.isSubrange | c.isFullRange); - if (c.isSubrange) - sum = c.sumInUnsignedRange(sum, (int)uval); - else - sum += (int)uval; - uval = (uint32_t)sum; - } - return getPopValue(this, uval); - - case cmk_pop_BHS0: - assert(S == 0 && D == 0); - uval = coding::parse(rp, B, H); - return getPopValue(this, uval); - - case cmk_pop_BYTE1: - assert(c.spec == BYTE1_spec); - assert(B == 1 && H == 256 && S == 0 && D == 0); - return getPopValue(this, *rp++ & 0xFF); - - default: - break; - } - assert(false); - return 0; -} - -static int moreCentral(int x, int y) -{ // used to find end of Pop.{F} - // Suggested implementation from the Pack200 specification: - uint32_t kx = (x >> 31) ^ (x << 1); - uint32_t ky = (y >> 31) ^ (y << 1); - return (kx < ky ? x : y); -} -// static maybe_inline -// int moreCentral2(int x, int y, int min) { -// // Strict implementation of buggy 150.7 specification. -// // The bug is that the spec. says absolute-value ties are broken -// // in favor of positive numbers, but the suggested implementation -// // (also mentioned in the spec.) breaks ties in favor of negative numbers. -// if ((x + y) != 0) -// return min; -// else -// // return the other value, which breaks a tie in the positive direction -// return (x > y)? x: y; -//} - -static const byte *no_meta[] = {nullptr}; -#define NO_META (*(byte **)no_meta) -enum -{ - POP_FAVORED_N = -2 -}; - -// mode bits -#define DISABLE_RUN 1 // used immediately inside ACodee -#define DISABLE_POP 2 // used recursively in all pop sub-bands - -// This function knows all about meta-coding. -void coding_method::init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int mode, - coding *defc, int N, intlist *valueSink) -{ - assert(N != 0); - - assert(u != nullptr); // must be pre-initialized - // if (u == nullptr) u = unpacker::current(); // expensive - - int op = (meta_rp == nullptr) ? _meta_default : (*meta_rp++ & 0xFF); - coding *foundc = nullptr; - coding *to_free = nullptr; - - if (op == _meta_default) - { - foundc = defc; - // and fall through - } - else if (op >= _meta_canon_min && op <= _meta_canon_max) - { - foundc = coding::findByIndex(op); - // and fall through - } - else if (op == _meta_arb) - { - int args = (*meta_rp++ & 0xFF); - // args = (D:[0..1] + 2*S[0..2] + 8*(B:[1..5]-1)) - int D = ((args >> 0) & 1); - int S = ((args >> 1) & 3); - int B = ((args >> 3) & -1) + 1; - // & (H[1..256]-1) - int H = (*meta_rp++ & 0xFF) + 1; - foundc = coding::findBySpec(B, H, S, D); - to_free = foundc; // findBySpec may dynamically allocate - if (foundc == nullptr) - { - unpack_abort("illegal arbitrary coding"); - return; - } - // and fall through - } - else if (op >= _meta_run && op < _meta_pop) - { - int args = (op - _meta_run); - // args: KX:[0..3] + 4*(KBFlag:[0..1]) + 8*(ABDef:[0..2]) - int KX = ((args >> 0) & 3); - int KBFlag = ((args >> 2) & 1); - int ABDef = ((args >> 3) & -1); - assert(ABDef <= 2); - // & KB: one of [0..255] if KBFlag=1 - int KB = (!KBFlag ? 3 : (*meta_rp++ & 0xFF)); - int K = (KB + 1) << (KX * 4); - int N2 = (N >= 0) ? N - K : N; - if (N == 0 || (N2 <= 0 && N2 != N)) - { - unpack_abort("illegal run encoding"); - } - if ((mode & DISABLE_RUN) != 0) - { - unpack_abort("illegal nested run encoding"); - } - - // & Enc{ ACode } if ADef=0 (ABDef != 1) - // No direct nesting of 'run' in ACode, but in BCode it's OK. - int disRun = mode | DISABLE_RUN; - if (ABDef == 1) - { - this->init(band_rp, band_limit, NO_META, disRun, defc, K, valueSink); - } - else - { - this->init(band_rp, band_limit, meta_rp, disRun, defc, K, valueSink); - } - - // & Enc{ BCode } if BDef=0 (ABDef != 2) - coding_method *tail = U_NEW(coding_method, 1); - if (!tail) - return; - tail->u = u; - - // The 'run' codings may be nested indirectly via 'pop' codings. - // This means that this->next may already be filled in, if - // ACode was of type 'pop' with a 'run' token coding. - // No problem: Just chain the upcoming BCode onto the end. - for (coding_method *self = this;; self = self->next) - { - if (self->next == nullptr) - { - self->next = tail; - break; - } - } - - if (ABDef == 2) - { - tail->init(band_rp, band_limit, NO_META, mode, defc, N2, valueSink); - } - else - { - tail->init(band_rp, band_limit, meta_rp, mode, defc, N2, valueSink); - } - // Note: The preceding calls to init should be tail-recursive. - - return; // done; no falling through - } - else if (op >= _meta_pop && op < _meta_limit) - { - int args = (op - _meta_pop); - // args: (FDef:[0..1]) + 2*UDef:[0..1] + 4*(TDefL:[0..11]) - int FDef = ((args >> 0) & 1); - int UDef = ((args >> 1) & 1); - int TDefL = ((args >> 2) & -1); - assert(TDefL <= 11); - int TDef = (TDefL > 0); - int TL = (TDefL <= 6) ? (2 << TDefL) : (256 - (4 << (11 - TDefL))); - int TH = (256 - TL); - if (N <= 0) - { - unpack_abort("illegal pop encoding"); - } - if ((mode & DISABLE_POP) != 0) - { - unpack_abort("illegal nested pop encoding"); - } - - // No indirect nesting of 'pop', but 'run' is OK. - int disPop = DISABLE_POP; - - // & Enc{ FCode } if FDef=0 - int FN = POP_FAVORED_N; - assert(valueSink == nullptr); - intlist fValueSink; - fValueSink.init(); - coding_method fval; - BYTES_OF(fval).clear(); - fval.u = u; - if (FDef != 0) - { - fval.init(band_rp, band_limit, NO_META, disPop, defc, FN, &fValueSink); - } - else - { - fval.init(band_rp, band_limit, meta_rp, disPop, defc, FN, &fValueSink); - } - bytes fvbuf; - fValues = (u->saveTo(fvbuf, fValueSink.b), (int *)fvbuf.ptr); - fVlength = fValueSink.length(); // i.e., the parameter K - fValueSink.free(); - - // Skip the first {F} run in all subsequent passes. - // The next call to this->init(...) will set vs0.rp to point after the {F}. - - // & Enc{ TCode } if TDef=0 (TDefL==0) - if (TDef != 0) - { - coding *tcode = coding::findBySpec(1, 256); // BYTE1 - // find the most narrowly sufficient code: - for (int B = 2; B <= B_MAX; B++) - { - if (fVlength <= tcode->umax) - break; // found it - tcode->free(); - tcode = coding::findBySpec(B, TH); - if (!tcode) - return; - } - if (!(fVlength <= tcode->umax)) - { - unpack_abort("pop.L value too small"); - } - this->init(band_rp, band_limit, NO_META, disPop, tcode, N, nullptr); - tcode->free(); - } - else - { - this->init(band_rp, band_limit, meta_rp, disPop, defc, N, nullptr); - } - - // Count the number of zero tokens right now. - // Also verify that they are in bounds. - int UN = 0; // one {U} for each zero in {T} - value_stream vs = vs0; - for (int i = 0; i < N; i++) - { - uint32_t val = vs.getInt(); - if (val == 0) - UN += 1; - if (!(val <= (uint32_t)fVlength)) - { - unpack_abort("pop token out of range"); - } - } - vs.done(); - - // & Enc{ UCode } if UDef=0 - if (UN != 0) - { - uValues = U_NEW(coding_method, 1); - if (uValues == nullptr) - return; - uValues->u = u; - if (UDef != 0) - { - uValues->init(band_rp, band_limit, NO_META, disPop, defc, UN, nullptr); - } - else - { - uValues->init(band_rp, band_limit, meta_rp, disPop, defc, UN, nullptr); - } - } - else - { - if (UDef == 0) - { - int uop = (*meta_rp++ & 0xFF); - if (uop > _meta_canon_max) - // %%% Spec. requires the more strict (uop != _meta_default). - unpack_abort("bad meta-coding for empty pop/U"); - } - } - - // Bug fix for 6259542 - // Last of all, adjust vs0.cmk to the 'pop' flavor - for (coding_method *self = this; self != nullptr; self = self->next) - { - coding_method_kind cmk2 = cmk_pop; - switch (self->vs0.cmk) - { - case cmk_BHS0: - cmk2 = cmk_pop_BHS0; - break; - case cmk_BYTE1: - cmk2 = cmk_pop_BYTE1; - break; - default: - break; - } - self->vs0.cmk = cmk2; - if (self != this) - { - assert(self->fValues == nullptr); // no double init - self->fValues = this->fValues; - self->fVlength = this->fVlength; - assert(self->uValues == nullptr); // must stay nullptr - } - } - - return; // done; no falling through - } - else - { - unpack_abort("bad meta-coding"); - } - - // Common code here skips a series of values with one coding. - assert(foundc != nullptr); - - assert(vs0.cmk == cmk_ERROR); // no garbage, please - assert(vs0.rp == nullptr); // no garbage, please - assert(vs0.rplimit == nullptr); // no garbage, please - assert(vs0.sum == 0); // no garbage, please - - vs0.init(band_rp, band_limit, foundc); - - // Done with foundc. Free if necessary. - if (to_free != nullptr) - { - to_free->free(); - to_free = nullptr; - } - foundc = nullptr; - - coding &c = vs0.c; - CODING_PRIVATE(c.spec); - // assert sane N - assert((uint32_t)N < INT_MAX_VALUE || N == POP_FAVORED_N); - - // Look at the values, or at least skip over them quickly. - if (valueSink == nullptr) - { - // Skip and ignore values in the first pass. - c.parseMultiple(band_rp, N, band_limit, B, H); - } - else if (N >= 0) - { - // Pop coding, {F} sequence, initial run of values... - assert((mode & DISABLE_POP) != 0); - value_stream vs = vs0; - for (int n = 0; n < N; n++) - { - int val = vs.getInt(); - valueSink->add(val); - } - band_rp = vs.rp; - } - else - { - // Pop coding, {F} sequence, final run of values... - assert((mode & DISABLE_POP) != 0); - assert(N == POP_FAVORED_N); - int min = INT_MIN_VALUE; // farthest from the center - // min2 is based on the buggy specification of centrality in version 150.7 - // no known implementations transmit this value, but just in case... - // int min2 = INT_MIN_VALUE; - int last = 0; - // if there were initial runs, find the potential sentinels in them: - for (int i = 0; i < valueSink->length(); i++) - { - last = valueSink->get(i); - min = moreCentral(min, last); - // min2 = moreCentral2(min2, last, min); - } - value_stream vs = vs0; - for (;;) - { - int val = vs.getInt(); - if (valueSink->length() > 0 && (val == last || val == min)) //|| val == min2 - break; - valueSink->add(val); - last = val; - min = moreCentral(min, last); - // min2 = moreCentral2(min2, last, min); - } - band_rp = vs.rp; - } - - // Get an accurate upper limit now. - vs0.rplimit = band_rp; - vs0.cm = this; - - return; // success -} - -coding basic_codings[] = { - // This one is not a usable irregular coding, but is used by cp_Utf8_chars. - CODING_INIT(3, 128, 0, 0), - - // Fixed-length codings: - CODING_INIT(1, 256, 0, 0), CODING_INIT(1, 256, 1, 0), CODING_INIT(1, 256, 0, 1), - CODING_INIT(1, 256, 1, 1), CODING_INIT(2, 256, 0, 0), CODING_INIT(2, 256, 1, 0), - CODING_INIT(2, 256, 0, 1), CODING_INIT(2, 256, 1, 1), CODING_INIT(3, 256, 0, 0), - CODING_INIT(3, 256, 1, 0), CODING_INIT(3, 256, 0, 1), CODING_INIT(3, 256, 1, 1), - CODING_INIT(4, 256, 0, 0), CODING_INIT(4, 256, 1, 0), CODING_INIT(4, 256, 0, 1), - CODING_INIT(4, 256, 1, 1), - - // Full-range variable-length codings: - CODING_INIT(5, 4, 0, 0), CODING_INIT(5, 4, 1, 0), CODING_INIT(5, 4, 2, 0), - CODING_INIT(5, 16, 0, 0), CODING_INIT(5, 16, 1, 0), CODING_INIT(5, 16, 2, 0), - CODING_INIT(5, 32, 0, 0), CODING_INIT(5, 32, 1, 0), CODING_INIT(5, 32, 2, 0), - CODING_INIT(5, 64, 0, 0), CODING_INIT(5, 64, 1, 0), CODING_INIT(5, 64, 2, 0), - CODING_INIT(5, 128, 0, 0), CODING_INIT(5, 128, 1, 0), CODING_INIT(5, 128, 2, 0), - CODING_INIT(5, 4, 0, 1), CODING_INIT(5, 4, 1, 1), CODING_INIT(5, 4, 2, 1), - CODING_INIT(5, 16, 0, 1), CODING_INIT(5, 16, 1, 1), CODING_INIT(5, 16, 2, 1), - CODING_INIT(5, 32, 0, 1), CODING_INIT(5, 32, 1, 1), CODING_INIT(5, 32, 2, 1), - CODING_INIT(5, 64, 0, 1), CODING_INIT(5, 64, 1, 1), CODING_INIT(5, 64, 2, 1), - CODING_INIT(5, 128, 0, 1), CODING_INIT(5, 128, 1, 1), CODING_INIT(5, 128, 2, 1), - - // Variable length subrange codings: - CODING_INIT(2, 192, 0, 0), CODING_INIT(2, 224, 0, 0), CODING_INIT(2, 240, 0, 0), - CODING_INIT(2, 248, 0, 0), CODING_INIT(2, 252, 0, 0), CODING_INIT(2, 8, 0, 1), - CODING_INIT(2, 8, 1, 1), CODING_INIT(2, 16, 0, 1), CODING_INIT(2, 16, 1, 1), - CODING_INIT(2, 32, 0, 1), CODING_INIT(2, 32, 1, 1), CODING_INIT(2, 64, 0, 1), - CODING_INIT(2, 64, 1, 1), CODING_INIT(2, 128, 0, 1), CODING_INIT(2, 128, 1, 1), - CODING_INIT(2, 192, 0, 1), CODING_INIT(2, 192, 1, 1), CODING_INIT(2, 224, 0, 1), - CODING_INIT(2, 224, 1, 1), CODING_INIT(2, 240, 0, 1), CODING_INIT(2, 240, 1, 1), - CODING_INIT(2, 248, 0, 1), CODING_INIT(2, 248, 1, 1), CODING_INIT(3, 192, 0, 0), - CODING_INIT(3, 224, 0, 0), CODING_INIT(3, 240, 0, 0), CODING_INIT(3, 248, 0, 0), - CODING_INIT(3, 252, 0, 0), CODING_INIT(3, 8, 0, 1), CODING_INIT(3, 8, 1, 1), - CODING_INIT(3, 16, 0, 1), CODING_INIT(3, 16, 1, 1), CODING_INIT(3, 32, 0, 1), - CODING_INIT(3, 32, 1, 1), CODING_INIT(3, 64, 0, 1), CODING_INIT(3, 64, 1, 1), - CODING_INIT(3, 128, 0, 1), CODING_INIT(3, 128, 1, 1), CODING_INIT(3, 192, 0, 1), - CODING_INIT(3, 192, 1, 1), CODING_INIT(3, 224, 0, 1), CODING_INIT(3, 224, 1, 1), - CODING_INIT(3, 240, 0, 1), CODING_INIT(3, 240, 1, 1), CODING_INIT(3, 248, 0, 1), - CODING_INIT(3, 248, 1, 1), CODING_INIT(4, 192, 0, 0), CODING_INIT(4, 224, 0, 0), - CODING_INIT(4, 240, 0, 0), CODING_INIT(4, 248, 0, 0), CODING_INIT(4, 252, 0, 0), - CODING_INIT(4, 8, 0, 1), CODING_INIT(4, 8, 1, 1), CODING_INIT(4, 16, 0, 1), - CODING_INIT(4, 16, 1, 1), CODING_INIT(4, 32, 0, 1), CODING_INIT(4, 32, 1, 1), - CODING_INIT(4, 64, 0, 1), CODING_INIT(4, 64, 1, 1), CODING_INIT(4, 128, 0, 1), - CODING_INIT(4, 128, 1, 1), CODING_INIT(4, 192, 0, 1), CODING_INIT(4, 192, 1, 1), - CODING_INIT(4, 224, 0, 1), CODING_INIT(4, 224, 1, 1), CODING_INIT(4, 240, 0, 1), - CODING_INIT(4, 240, 1, 1), CODING_INIT(4, 248, 0, 1), CODING_INIT(4, 248, 1, 1), - CODING_INIT(0, 0, 0, 0)}; -#define BASIC_INDEX_LIMIT (int)(sizeof(basic_codings) / sizeof(basic_codings[0]) - 1) - -coding *coding::findByIndex(int idx) -{ - int index_limit = BASIC_INDEX_LIMIT; - assert(_meta_canon_min == 1 && _meta_canon_max + 1 == index_limit); - - if (idx >= _meta_canon_min && idx <= _meta_canon_max) - return basic_codings[idx].init(); - else - return nullptr; -} diff --git a/libraries/pack200/src/coding.h b/libraries/pack200/src/coding.h deleted file mode 100644 index bfdd252e..00000000 --- a/libraries/pack200/src/coding.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -struct unpacker; - -#define INT_MAX_VALUE ((int)0x7FFFFFFF) -#define INT_MIN_VALUE ((int)0x80000000) - -#define CODING_SPEC(B, H, S, D) ((B) << 20 | (H) << 8 | (S) << 4 | (D) << 0) -#define CODING_B(x) ((x) >> 20 & 0xF) -#define CODING_H(x) ((x) >> 8 & 0xFFF) -#define CODING_S(x) ((x) >> 4 & 0xF) -#define CODING_D(x) ((x) >> 0 & 0xF) - -#define CODING_INIT(B, H, S, D) \ - { \ - CODING_SPEC(B, H, S, D), 0, 0, 0, 0, 0, 0, 0, 0 \ - } - -// For debugging purposes, some compilers do not like this and will complain. -// #define long do_not_use_C_long_types_use_jlong_or_int -// Use of the type "long" is problematic, do not use it. - -struct coding -{ - int spec; // B,H,S,D - - // Handy values derived from the spec: - int B() - { - return CODING_B(spec); - } - int H() - { - return CODING_H(spec); - } - int S() - { - return CODING_S(spec); - } - int D() - { - return CODING_D(spec); - } - int L() - { - return 256 - CODING_H(spec); - } - int min, max; - int umin, umax; - char isSigned, isSubrange, isFullRange, isMalloc; - - coding *init(); // returns self or nullptr if error - coding *initFrom(int spec_) - { - assert(this->spec == 0); - this->spec = spec_; - return init(); - } - - static coding *findBySpec(int spec); - static coding *findBySpec(int B, int H, int S = 0, int D = 0); - static coding *findByIndex(int irregularCodingIndex); - - static uint32_t parse(byte *&rp, int B, int H); - static uint32_t parse_lgH(byte *&rp, int B, int H, int lgH); - static void parseMultiple(byte *&rp, int N, byte *limit, int B, int H); - - uint32_t parse(byte *&rp) - { - return parse(rp, CODING_B(spec), CODING_H(spec)); - } - void parseMultiple(byte *&rp, int N, byte *limit) - { - parseMultiple(rp, N, limit, CODING_B(spec), CODING_H(spec)); - } - - bool canRepresent(int x) - { - return (x >= min && x <= max); - } - bool canRepresentUnsigned(int x) - { - return (x >= umin && x <= umax); - } - - int sumInUnsignedRange(int x, int y); - - int readFrom(byte *&rpVar, int *dbase); - void readArrayFrom(byte *&rpVar, int *dbase, int length, int *values); - void skipArrayFrom(byte *&rpVar, int length) - { - readArrayFrom(rpVar, (int *)NULL, length, (int *)NULL); - } - - void free(); // free self if isMalloc -}; - -enum coding_method_kind -{ - cmk_ERROR, - cmk_BHS, - cmk_BHS0, - cmk_BHS1, - cmk_BHSD1, - cmk_BHS1D1full, // isFullRange - cmk_BHS1D1sub, // isSubRange - - // special cases hand-optimized (~50% of all decoded values) - cmk_BYTE1, //(1,256) 6% - cmk_CHAR3, //(3,128) 7% - cmk_UNSIGNED5, //(5,64) 13% - cmk_DELTA5, //(5,64,1,1) 5% - cmk_BCI5, //(5,4) 18% - cmk_BRANCH5, //(5,4,2) 4% - // cmk_UNSIGNED5H16, //(5,16) 5% - // cmk_UNSIGNED2H4, //(2,4) 6% - // cmk_DELTA4H8, //(4,8,1,1) 10% - // cmk_DELTA3H16, //(3,16,1,1) 9% - cmk_BHS_LIMIT, - cmk_pop, - cmk_pop_BHS0, - cmk_pop_BYTE1, - cmk_pop_LIMIT, - cmk_LIMIT -}; - -enum -{ - BYTE1_spec = CODING_SPEC(1, 256, 0, 0), - CHAR3_spec = CODING_SPEC(3, 128, 0, 0), - UNSIGNED4_spec = CODING_SPEC(4, 256, 0, 0), - UNSIGNED5_spec = CODING_SPEC(5, 64, 0, 0), - SIGNED5_spec = CODING_SPEC(5, 64, 1, 0), - DELTA5_spec = CODING_SPEC(5, 64, 1, 1), - UDELTA5_spec = CODING_SPEC(5, 64, 0, 1), - MDELTA5_spec = CODING_SPEC(5, 64, 2, 1), - BCI5_spec = CODING_SPEC(5, 4, 0, 0), - BRANCH5_spec = CODING_SPEC(5, 4, 2, 0) -}; - -enum -{ - B_MAX = 5, - C_SLOP = B_MAX * 10 -}; - -struct coding_method; - -// iterator under the control of a meta-coding -struct value_stream -{ - // current coding of values or values - coding c; // B,H,S,D,etc. - coding_method_kind cmk; // type of decoding needed - byte *rp; // read pointer - byte *rplimit; // final value of read pointer - int sum; // partial sum of all values so far (D=1 only) - coding_method *cm; // coding method that defines this stream - - void init(byte *band_rp, byte *band_limit, coding *defc); - void init(byte *band_rp, byte *band_limit, int spec) - { - init(band_rp, band_limit, coding::findBySpec(spec)); - } - - void setCoding(coding *c); - void setCoding(int spec) - { - setCoding(coding::findBySpec(spec)); - } - - // Parse and decode a single value. - int getInt(); - - // Parse and decode a single byte, with no error checks. - int getByte() - { - assert(cmk == cmk_BYTE1); - assert(rp < rplimit); - return *rp++ & 0xFF; - } - - // Used only for asserts. - bool hasValue(); - - void done() - { - assert(!hasValue()); - } - - // Sometimes a value stream has an auxiliary (but there are never two). - value_stream *helper() - { - assert(hasHelper()); - return this + 1; - } - bool hasHelper(); -}; - -struct coding_method -{ - value_stream vs0; // initial state snapshot (vs.meta==this) - - coding_method *next; // what to do when we run out of bytes - - // these fields are used for pop codes only: - int *fValues; // favored value array - int fVlength; // maximum favored value token - coding_method *uValues; // unfavored value stream - - // pointer to outer unpacker, for error checks etc. - unpacker *u; - - // Initialize a value stream. - void reset(value_stream *state); - - // Parse a band header, size a band, and initialize for further action. - // band_rp advances (but not past band_limit), and meta_rp advances. - // The mode gives context, such as "inside a pop". - // The defc and N are the incoming parameters to a meta-coding. - // The value sink is used to collect output values, when desired. - void init(byte *&band_rp, byte *band_limit, byte *&meta_rp, int mode, coding *defc, int N, - intlist *valueSink); -}; diff --git a/libraries/pack200/src/constants.h b/libraries/pack200/src/constants.h deleted file mode 100644 index f1baf42a..00000000 --- a/libraries/pack200/src/constants.h +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - Java Class Version numbers history - 1.0 to 1.3.X 45,3 - 1.4 to 1.4.X 46,0 - 1.5 to 1.5.X 49,0 - 1.6 to 1.5.x 50,0 NOTE Assumed for now -*/ - -// classfile constants -#define JAVA_MAGIC 0xCAFEBABE -#define JAVA_MIN_MAJOR_VERSION 45 -#define JAVA_MIN_MINOR_VERSION 3 -#define JAVA5_MAX_MAJOR_VERSION 49 -#define JAVA5_MAX_MINOR_VERSION 0 -// NOTE: Assume for now -#define JAVA6_MAX_MAJOR_VERSION 50 -#define JAVA6_MAX_MINOR_VERSION 0 - -// package file constants -#define JAVA_PACKAGE_MAGIC 0xCAFED00D -#define JAVA5_PACKAGE_MAJOR_VERSION 150 -#define JAVA5_PACKAGE_MINOR_VERSION 7 - -#define JAVA6_PACKAGE_MAJOR_VERSION 160 -#define JAVA6_PACKAGE_MINOR_VERSION 1 - -// magic number for gzip streams (for processing pack200-gzip data) -#define GZIP_MAGIC 0x1F8B0800 -#define GZIP_MAGIC_MASK 0xFFFFFF00 // last \bchar\b is variable "flg" field - -enum -{ - CONSTANT_None, - CONSTANT_Utf8, - CONSTANT_unused2, /* unused, was Unicode */ - CONSTANT_Integer, - CONSTANT_Float, - CONSTANT_Long, - CONSTANT_Double, - CONSTANT_Class, - CONSTANT_String, - CONSTANT_Fieldref, - CONSTANT_Methodref, - CONSTANT_InterfaceMethodref, - CONSTANT_NameandType, - CONSTANT_Signature = 13, - CONSTANT_All = 14, - CONSTANT_Limit = 15, - CONSTANT_NONE = 0, - CONSTANT_Literal = 20, // pseudo-tag for debugging - CONSTANT_Member = 21, // pseudo-tag for debugging - SUBINDEX_BIT = 64, // combined with CONSTANT_xxx for ixTag - ACC_STATIC = 0x0008, - ACC_IC_LONG_FORM = (1 << 16), // for ic_flags - CLASS_ATTR_SourceFile = 17, - CLASS_ATTR_EnclosingMethod = 18, - CLASS_ATTR_InnerClasses = 23, - CLASS_ATTR_ClassFile_version = 24, - FIELD_ATTR_ConstantValue = 17, - METHOD_ATTR_Code = 17, - METHOD_ATTR_Exceptions = 18, - METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23, - METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24, - METHOD_ATTR_AnnotationDefault = 25, - CODE_ATTR_StackMapTable = 0, - CODE_ATTR_LineNumberTable = 1, - CODE_ATTR_LocalVariableTable = 2, - CODE_ATTR_LocalVariableTypeTable = 3, - // X_ATTR_Synthetic = 12, // ACC_SYNTHETIC; not predefined - X_ATTR_Signature = 19, - X_ATTR_Deprecated = 20, - X_ATTR_RuntimeVisibleAnnotations = 21, - X_ATTR_RuntimeInvisibleAnnotations = 22, - X_ATTR_OVERFLOW = 16, - X_ATTR_LIMIT_NO_FLAGS_HI = 32, - X_ATTR_LIMIT_FLAGS_HI = 63, - -#define O_ATTR_DO(F) \ - F(X_ATTR_OVERFLOW, 01) \ - /*(end)*/ -#define X_ATTR_DO(F) \ - O_ATTR_DO(F) F(X_ATTR_Signature, Signature) F(X_ATTR_Deprecated, Deprecated) \ - F(X_ATTR_RuntimeVisibleAnnotations, RuntimeVisibleAnnotations) \ - F(X_ATTR_RuntimeInvisibleAnnotations, RuntimeInvisibleAnnotations) \ - /*F(X_ATTR_Synthetic,Synthetic)*/ \ - /*(end)*/ -#define CLASS_ATTR_DO(F) \ - F(CLASS_ATTR_SourceFile, SourceFile) F(CLASS_ATTR_InnerClasses, InnerClasses) \ - F(CLASS_ATTR_EnclosingMethod, EnclosingMethod) F(CLASS_ATTR_ClassFile_version, 02) \ - /*(end)*/ -#define FIELD_ATTR_DO(F) \ - F(FIELD_ATTR_ConstantValue, ConstantValue) \ - /*(end)*/ -#define METHOD_ATTR_DO(F) \ - F(METHOD_ATTR_Code, Code) F(METHOD_ATTR_Exceptions, Exceptions) \ - F(METHOD_ATTR_RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations) \ - F(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, \ - RuntimeInvisibleParameterAnnotations) \ - F(METHOD_ATTR_AnnotationDefault, AnnotationDefault) \ - /*(end)*/ -#define CODE_ATTR_DO(F) \ - F(CODE_ATTR_StackMapTable, StackMapTable) F(CODE_ATTR_LineNumberTable, LineNumberTable) \ - F(CODE_ATTR_LocalVariableTable, LocalVariableTable) \ - F(CODE_ATTR_LocalVariableTypeTable, LocalVariableTypeTable) \ - /*(end)*/ -#define ALL_ATTR_DO(F) \ - X_ATTR_DO(F) CLASS_ATTR_DO(F) FIELD_ATTR_DO(F) METHOD_ATTR_DO(F) CODE_ATTR_DO(F) \ - /*(end)*/ - - // attribute "context types" - ATTR_CONTEXT_CLASS = 0, - ATTR_CONTEXT_FIELD = 1, - ATTR_CONTEXT_METHOD = 2, - ATTR_CONTEXT_CODE = 3, - ATTR_CONTEXT_LIMIT = 4, - - // constants for parsed layouts (stored in band::le_kind) - EK_NONE = 0, // not a layout element - EK_INT = 'I', // B H I SH etc., also FH etc. - EK_BCI = 'P', // PH etc. - EK_BCID = 'Q', // POH etc. - EK_BCO = 'O', // OH etc. - EK_REPL = 'N', // NH[...] etc. - EK_REF = 'R', // RUH, RUNH, KQH, etc. - EK_UN = 'T', // TB(...)[...] etc. - EK_CASE = 'K', // (...)[...] etc. - EK_CALL = '(', // (0), (1), etc. - EK_CBLE = '[', // [...][...] etc. - NO_BAND_INDEX = -1, - - // File option bits, from LSB in ascending bit position. - FO_DEFLATE_HINT = 1 << 0, - FO_IS_CLASS_STUB = 1 << 1, - - // Archive option bits, from LSB in ascending bit position: - AO_HAVE_SPECIAL_FORMATS = 1 << 0, - AO_HAVE_CP_NUMBERS = 1 << 1, - AO_HAVE_ALL_CODE_FLAGS = 1 << 2, - AO_3_UNUSED_MBZ = 1 << 3, - AO_HAVE_FILE_HEADERS = 1 << 4, - AO_DEFLATE_HINT = 1 << 5, - AO_HAVE_FILE_MODTIME = 1 << 6, - AO_HAVE_FILE_OPTIONS = 1 << 7, - AO_HAVE_FILE_SIZE_HI = 1 << 8, - AO_HAVE_CLASS_FLAGS_HI = 1 << 9, - AO_HAVE_FIELD_FLAGS_HI = 1 << 10, - AO_HAVE_METHOD_FLAGS_HI = 1 << 11, - AO_HAVE_CODE_FLAGS_HI = 1 << 12, -#define ARCHIVE_BIT_DO(F) \ - F(AO_HAVE_SPECIAL_FORMATS) F(AO_HAVE_CP_NUMBERS) F(AO_HAVE_ALL_CODE_FLAGS) \ - /*F(AO_3_UNUSED_MBZ)*/ \ - F(AO_HAVE_FILE_HEADERS) F(AO_DEFLATE_HINT) F(AO_HAVE_FILE_MODTIME) \ - F(AO_HAVE_FILE_OPTIONS) F(AO_HAVE_FILE_SIZE_HI) F(AO_HAVE_CLASS_FLAGS_HI) \ - F(AO_HAVE_FIELD_FLAGS_HI) F(AO_HAVE_METHOD_FLAGS_HI) F(AO_HAVE_CODE_FLAGS_HI) \ - /*(end)*/ - - // Constants for decoding attribute definition header bytes. - ADH_CONTEXT_MASK = 0x3, // (hdr & ADH_CONTEXT_MASK) - ADH_BIT_SHIFT = 0x2, // (hdr >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB = 1, // (hdr >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB -#define ADH_BYTE(context, index) ((((index) + ADH_BIT_IS_LSB) << ADH_BIT_SHIFT) + (context)) -#define ADH_BYTE_CONTEXT(adhb) ((adhb) & ADH_CONTEXT_MASK) -#define ADH_BYTE_INDEX(adhb) (((adhb) >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB) - NO_MODTIME = 0, // nullptr modtime value - - // meta-coding - _meta_default = 0, - _meta_canon_min = 1, - _meta_canon_max = 115, - _meta_arb = 116, - _meta_run = 117, - _meta_pop = 141, - _meta_limit = 189, - _meta_error = 255, - _xxx_1_end -}; - -// Bytecodes. - -enum -{ - bc_nop = 0, // 0x00 - bc_aconst_null = 1, // 0x01 - bc_iconst_m1 = 2, // 0x02 - bc_iconst_0 = 3, // 0x03 - bc_iconst_1 = 4, // 0x04 - bc_iconst_2 = 5, // 0x05 - bc_iconst_3 = 6, // 0x06 - bc_iconst_4 = 7, // 0x07 - bc_iconst_5 = 8, // 0x08 - bc_lconst_0 = 9, // 0x09 - bc_lconst_1 = 10, // 0x0a - bc_fconst_0 = 11, // 0x0b - bc_fconst_1 = 12, // 0x0c - bc_fconst_2 = 13, // 0x0d - bc_dconst_0 = 14, // 0x0e - bc_dconst_1 = 15, // 0x0f - bc_bipush = 16, // 0x10 - bc_sipush = 17, // 0x11 - bc_ldc = 18, // 0x12 - bc_ldc_w = 19, // 0x13 - bc_ldc2_w = 20, // 0x14 - bc_iload = 21, // 0x15 - bc_lload = 22, // 0x16 - bc_fload = 23, // 0x17 - bc_dload = 24, // 0x18 - bc_aload = 25, // 0x19 - bc_iload_0 = 26, // 0x1a - bc_iload_1 = 27, // 0x1b - bc_iload_2 = 28, // 0x1c - bc_iload_3 = 29, // 0x1d - bc_lload_0 = 30, // 0x1e - bc_lload_1 = 31, // 0x1f - bc_lload_2 = 32, // 0x20 - bc_lload_3 = 33, // 0x21 - bc_fload_0 = 34, // 0x22 - bc_fload_1 = 35, // 0x23 - bc_fload_2 = 36, // 0x24 - bc_fload_3 = 37, // 0x25 - bc_dload_0 = 38, // 0x26 - bc_dload_1 = 39, // 0x27 - bc_dload_2 = 40, // 0x28 - bc_dload_3 = 41, // 0x29 - bc_aload_0 = 42, // 0x2a - bc_aload_1 = 43, // 0x2b - bc_aload_2 = 44, // 0x2c - bc_aload_3 = 45, // 0x2d - bc_iaload = 46, // 0x2e - bc_laload = 47, // 0x2f - bc_faload = 48, // 0x30 - bc_daload = 49, // 0x31 - bc_aaload = 50, // 0x32 - bc_baload = 51, // 0x33 - bc_caload = 52, // 0x34 - bc_saload = 53, // 0x35 - bc_istore = 54, // 0x36 - bc_lstore = 55, // 0x37 - bc_fstore = 56, // 0x38 - bc_dstore = 57, // 0x39 - bc_astore = 58, // 0x3a - bc_istore_0 = 59, // 0x3b - bc_istore_1 = 60, // 0x3c - bc_istore_2 = 61, // 0x3d - bc_istore_3 = 62, // 0x3e - bc_lstore_0 = 63, // 0x3f - bc_lstore_1 = 64, // 0x40 - bc_lstore_2 = 65, // 0x41 - bc_lstore_3 = 66, // 0x42 - bc_fstore_0 = 67, // 0x43 - bc_fstore_1 = 68, // 0x44 - bc_fstore_2 = 69, // 0x45 - bc_fstore_3 = 70, // 0x46 - bc_dstore_0 = 71, // 0x47 - bc_dstore_1 = 72, // 0x48 - bc_dstore_2 = 73, // 0x49 - bc_dstore_3 = 74, // 0x4a - bc_astore_0 = 75, // 0x4b - bc_astore_1 = 76, // 0x4c - bc_astore_2 = 77, // 0x4d - bc_astore_3 = 78, // 0x4e - bc_iastore = 79, // 0x4f - bc_lastore = 80, // 0x50 - bc_fastore = 81, // 0x51 - bc_dastore = 82, // 0x52 - bc_aastore = 83, // 0x53 - bc_bastore = 84, // 0x54 - bc_castore = 85, // 0x55 - bc_sastore = 86, // 0x56 - bc_pop = 87, // 0x57 - bc_pop2 = 88, // 0x58 - bc_dup = 89, // 0x59 - bc_dup_x1 = 90, // 0x5a - bc_dup_x2 = 91, // 0x5b - bc_dup2 = 92, // 0x5c - bc_dup2_x1 = 93, // 0x5d - bc_dup2_x2 = 94, // 0x5e - bc_swap = 95, // 0x5f - bc_iadd = 96, // 0x60 - bc_ladd = 97, // 0x61 - bc_fadd = 98, // 0x62 - bc_dadd = 99, // 0x63 - bc_isub = 100, // 0x64 - bc_lsub = 101, // 0x65 - bc_fsub = 102, // 0x66 - bc_dsub = 103, // 0x67 - bc_imul = 104, // 0x68 - bc_lmul = 105, // 0x69 - bc_fmul = 106, // 0x6a - bc_dmul = 107, // 0x6b - bc_idiv = 108, // 0x6c - bc_ldiv = 109, // 0x6d - bc_fdiv = 110, // 0x6e - bc_ddiv = 111, // 0x6f - bc_irem = 112, // 0x70 - bc_lrem = 113, // 0x71 - bc_frem = 114, // 0x72 - bc_drem = 115, // 0x73 - bc_ineg = 116, // 0x74 - bc_lneg = 117, // 0x75 - bc_fneg = 118, // 0x76 - bc_dneg = 119, // 0x77 - bc_ishl = 120, // 0x78 - bc_lshl = 121, // 0x79 - bc_ishr = 122, // 0x7a - bc_lshr = 123, // 0x7b - bc_iushr = 124, // 0x7c - bc_lushr = 125, // 0x7d - bc_iand = 126, // 0x7e - bc_land = 127, // 0x7f - bc_ior = 128, // 0x80 - bc_lor = 129, // 0x81 - bc_ixor = 130, // 0x82 - bc_lxor = 131, // 0x83 - bc_iinc = 132, // 0x84 - bc_i2l = 133, // 0x85 - bc_i2f = 134, // 0x86 - bc_i2d = 135, // 0x87 - bc_l2i = 136, // 0x88 - bc_l2f = 137, // 0x89 - bc_l2d = 138, // 0x8a - bc_f2i = 139, // 0x8b - bc_f2l = 140, // 0x8c - bc_f2d = 141, // 0x8d - bc_d2i = 142, // 0x8e - bc_d2l = 143, // 0x8f - bc_d2f = 144, // 0x90 - bc_i2b = 145, // 0x91 - bc_i2c = 146, // 0x92 - bc_i2s = 147, // 0x93 - bc_lcmp = 148, // 0x94 - bc_fcmpl = 149, // 0x95 - bc_fcmpg = 150, // 0x96 - bc_dcmpl = 151, // 0x97 - bc_dcmpg = 152, // 0x98 - bc_ifeq = 153, // 0x99 - bc_ifne = 154, // 0x9a - bc_iflt = 155, // 0x9b - bc_ifge = 156, // 0x9c - bc_ifgt = 157, // 0x9d - bc_ifle = 158, // 0x9e - bc_if_icmpeq = 159, // 0x9f - bc_if_icmpne = 160, // 0xa0 - bc_if_icmplt = 161, // 0xa1 - bc_if_icmpge = 162, // 0xa2 - bc_if_icmpgt = 163, // 0xa3 - bc_if_icmple = 164, // 0xa4 - bc_if_acmpeq = 165, // 0xa5 - bc_if_acmpne = 166, // 0xa6 - bc_goto = 167, // 0xa7 - bc_jsr = 168, // 0xa8 - bc_ret = 169, // 0xa9 - bc_tableswitch = 170, // 0xaa - bc_lookupswitch = 171, // 0xab - bc_ireturn = 172, // 0xac - bc_lreturn = 173, // 0xad - bc_freturn = 174, // 0xae - bc_dreturn = 175, // 0xaf - bc_areturn = 176, // 0xb0 - bc_return = 177, // 0xb1 - bc_getstatic = 178, // 0xb2 - bc_putstatic = 179, // 0xb3 - bc_getfield = 180, // 0xb4 - bc_putfield = 181, // 0xb5 - bc_invokevirtual = 182, // 0xb6 - bc_invokespecial = 183, // 0xb7 - bc_invokestatic = 184, // 0xb8 - bc_invokeinterface = 185, // 0xb9 - bc_xxxunusedxxx = 186, // 0xba - bc_new = 187, // 0xbb - bc_newarray = 188, // 0xbc - bc_anewarray = 189, // 0xbd - bc_arraylength = 190, // 0xbe - bc_athrow = 191, // 0xbf - bc_checkcast = 192, // 0xc0 - bc_instanceof = 193, // 0xc1 - bc_monitorenter = 194, // 0xc2 - bc_monitorexit = 195, // 0xc3 - bc_wide = 196, // 0xc4 - bc_multianewarray = 197, // 0xc5 - bc_ifnull = 198, // 0xc6 - bc_ifnonnull = 199, // 0xc7 - bc_goto_w = 200, // 0xc8 - bc_jsr_w = 201, // 0xc9 - bc_bytecode_limit = 202 // 0xca -}; - -enum -{ - bc_end_marker = 255, - bc_byte_escape = 254, - bc_ref_escape = 253, - _first_linker_op = bc_getstatic, - _last_linker_op = bc_invokestatic, - _num_linker_ops = (_last_linker_op - _first_linker_op) + 1, - _self_linker_op = bc_bytecode_limit, - _self_linker_aload_flag = 1 * _num_linker_ops, - _self_linker_super_flag = 2 * _num_linker_ops, - _self_linker_limit = _self_linker_op + 4 * _num_linker_ops, - _invokeinit_op = _self_linker_limit, - _invokeinit_self_option = 0, - _invokeinit_super_option = 1, - _invokeinit_new_option = 2, - _invokeinit_limit = _invokeinit_op + 3, - _xldc_op = _invokeinit_limit, - bc_aldc = bc_ldc, - bc_cldc = _xldc_op + 0, - bc_ildc = _xldc_op + 1, - bc_fldc = _xldc_op + 2, - bc_aldc_w = bc_ldc_w, - bc_cldc_w = _xldc_op + 3, - bc_ildc_w = _xldc_op + 4, - bc_fldc_w = _xldc_op + 5, - bc_lldc2_w = bc_ldc2_w, - bc_dldc2_w = _xldc_op + 6, - _xldc_limit = _xldc_op + 7, - _xxx_3_end -}; diff --git a/libraries/pack200/src/defines.h b/libraries/pack200/src/defines.h deleted file mode 100644 index cfe5fc28..00000000 --- a/libraries/pack200/src/defines.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// random definitions - -#ifdef _MSC_VER -#include -#include -#else -#include -#endif - -// Error messages that we have -#define ERROR_ENOMEM "Memory allocation failed" -#define ERROR_FORMAT "Corrupted pack file" -#define ERROR_RESOURCE "Cannot extract resource file" -#define ERROR_OVERFLOW "Internal buffer overflow" -#define ERROR_INTERNAL "Internal error" - -#define lengthof(array) (sizeof(array) / sizeof(array[0])) - -#define NEW(T, n) (T *) must_malloc((int)(scale_size(n, sizeof(T)))) -#define U_NEW(T, n) (T *) u->alloc(scale_size(n, sizeof(T))) -#define T_NEW(T, n) (T *) u->temp_alloc(scale_size(n, sizeof(T))) - -typedef signed char byte; - -#ifdef _MSC_VER -#define MKDIR(dir) mkdir(dir) -#define getpid() _getpid() -#define PATH_MAX MAX_PATH -#define dup2(a, b) _dup2(a, b) -#define strcasecmp(s1, s2) _stricmp(s1, s2) -#define tempname _tempname -#define sleep Sleep -#else -#define MKDIR(dir) mkdir(dir, 0777); -#endif - -/* Must cast to void *, then size_t, then int. */ -#define ptrlowbits(x) ((int)(size_t)(void *)(x)) - -#define DEFAULT_ARCHIVE_MODTIME 1060000000 // Aug 04, 2003 5:26 PM PDT diff --git a/libraries/pack200/src/unpack.cpp b/libraries/pack200/src/unpack.cpp deleted file mode 100644 index 9c4c633c..00000000 --- a/libraries/pack200/src/unpack.cpp +++ /dev/null @@ -1,4790 +0,0 @@ -/* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// -*- C++ -*- -// Program for unpacking specially compressed Java packages. -// John R. Rose - -/* - * When compiling for a 64bit LP64 system (longs and pointers being 64bits), - * the printf format %ld is correct and use of %lld will cause warning - * errors from some compilers (gcc/g++). - * _LP64 can be explicitly set (used on Linux). - * Solaris compilers will define __sparcv9 or __x86_64 on 64bit compilations. - */ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "defines.h" -#include "bytes.h" -#include "utils.h" -#include "coding.h" -#include "bands.h" - -#include "constants.h" - -#include "zip.h" - -#include "unpack.h" - -// tags, in canonical order: -static const byte TAGS_IN_ORDER[] = { - CONSTANT_Utf8, CONSTANT_Integer, CONSTANT_Float, CONSTANT_Long, - CONSTANT_Double, CONSTANT_String, CONSTANT_Class, CONSTANT_Signature, - CONSTANT_NameandType, CONSTANT_Fieldref, CONSTANT_Methodref, CONSTANT_InterfaceMethodref}; -#define N_TAGS_IN_ORDER (sizeof TAGS_IN_ORDER) - -// REQUESTED must be -2 for u2 and REQUESTED_LDC must be -1 for u1 -enum -{ - NOT_REQUESTED = 0, - REQUESTED = -2, - REQUESTED_LDC = -1 -}; - -#define NO_INORD ((uint32_t) - 1) - -struct entry -{ - byte tag; - unsigned short nrefs; // pack w/ tag - - int outputIndex; - uint32_t inord; // &cp.entries[cp.tag_base[this->tag]+this->inord] == this - - entry **refs; - - // put last to pack best - union - { - bytes b; - int i; - int64_t l; - } value; - - void requestOutputIndex(constant_pool &cp, int req = REQUESTED); - int getOutputIndex() - { - assert(outputIndex > NOT_REQUESTED); - return outputIndex; - } - - entry *ref(int refnum) - { - assert((uint32_t)refnum < nrefs); - return refs[refnum]; - } - - const char *utf8String() - { - assert(tagMatches(CONSTANT_Utf8)); - assert(value.b.len == strlen((const char *)value.b.ptr)); - return (const char *)value.b.ptr; - } - - entry *className() - { - assert(tagMatches(CONSTANT_Class)); - return ref(0); - } - - entry *memberClass() - { - assert(tagMatches(CONSTANT_Member)); - return ref(0); - } - - entry *memberDescr() - { - assert(tagMatches(CONSTANT_Member)); - return ref(1); - } - - entry *descrName() - { - assert(tagMatches(CONSTANT_NameandType)); - return ref(0); - } - - entry *descrType() - { - assert(tagMatches(CONSTANT_NameandType)); - return ref(1); - } - - int typeSize(); - - bytes &asUtf8(); - int asInteger() - { - assert(tag == CONSTANT_Integer); - return value.i; - } - - bool isUtf8(bytes &b) - { - return tagMatches(CONSTANT_Utf8) && value.b.equals(b); - } - - bool isDoubleWord() - { - return tag == CONSTANT_Double || tag == CONSTANT_Long; - } - - bool tagMatches(byte tag2) - { - return (tag2 == tag) || (tag2 == CONSTANT_Utf8 && tag == CONSTANT_Signature) || - (tag2 == CONSTANT_Literal && tag >= CONSTANT_Integer && tag <= CONSTANT_String && - tag != CONSTANT_Class) || - (tag2 == CONSTANT_Member && tag >= CONSTANT_Fieldref && - tag <= CONSTANT_InterfaceMethodref); - } -}; - -entry *cpindex::get(uint32_t i) -{ - if (i >= len) - return nullptr; - else if (base1 != nullptr) - // primary index - return &base1[i]; - else - // secondary index - return base2[i]; -} - -inline bytes &entry::asUtf8() -{ - assert(tagMatches(CONSTANT_Utf8)); - return value.b; -} - -int entry::typeSize() -{ - assert(tagMatches(CONSTANT_Utf8)); - const char *sigp = (char *)value.b.ptr; - switch (*sigp) - { - case '(': - sigp++; - break; // skip opening '(' - case 'D': - case 'J': - return 2; // double field - default: - return 1; // field - } - int siglen = 0; - for (;;) - { - int ch = *sigp++; - switch (ch) - { - case 'D': - case 'J': - siglen += 1; - break; - case '[': - // Skip rest of array info. - while (ch == '[') - { - ch = *sigp++; - } - if (ch != 'L') - break; - // else fall through - case 'L': - sigp = strchr(sigp, ';'); - if (sigp == nullptr) - { - unpack_abort("bad data"); - return 0; - } - sigp += 1; - break; - case ')': // closing ')' - return siglen; - } - siglen += 1; - } -} - -inline cpindex *constant_pool::getFieldIndex(entry *classRef) -{ - assert(classRef->tagMatches(CONSTANT_Class)); - assert((uint32_t)classRef->inord < (uint32_t)tag_count[CONSTANT_Class]); - return &member_indexes[classRef->inord * 2 + 0]; -} -inline cpindex *constant_pool::getMethodIndex(entry *classRef) -{ - assert(classRef->tagMatches(CONSTANT_Class)); - assert((uint32_t)classRef->inord < (uint32_t)tag_count[CONSTANT_Class]); - return &member_indexes[classRef->inord * 2 + 1]; -} - -struct inner_class -{ - entry *inner; - entry *outer; - entry *name; - int flags; - inner_class *next_sibling; - bool requested; -}; - -// Here is where everything gets deallocated: -void unpacker::free() -{ - int i; - if (jarout != nullptr) - jarout->reset(); - if (gzin != nullptr) - { - gzin->free(); - gzin = nullptr; - } - if (free_input) - input.free(); - /* - * free everybody ever allocated with U_NEW or (recently) with T_NEW - */ - assert(smallbuf.base() == nullptr || mallocs.contains(smallbuf.base())); - assert(tsmallbuf.base() == nullptr || tmallocs.contains(tsmallbuf.base())); - mallocs.freeAll(); - tmallocs.freeAll(); - smallbuf.init(); - tsmallbuf.init(); - bcimap.free(); - class_fixup_type.free(); - class_fixup_offset.free(); - class_fixup_ref.free(); - code_fixup_type.free(); - code_fixup_offset.free(); - code_fixup_source.free(); - requested_ics.free(); - cur_classfile_head.free(); - cur_classfile_tail.free(); - for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) - attr_defs[i].free(); - - // free CP state - cp.outputEntries.free(); - for (i = 0; i < CONSTANT_Limit; i++) - cp.tag_extras[i].free(); -} - -// input handling -// Attempts to advance rplimit so that (rplimit-rp) is at least 'more'. -// Will eagerly read ahead by larger chunks, if possible. -// Returns false if (rplimit-rp) is not at least 'more', -// unless rplimit hits input.limit(). -bool unpacker::ensure_input(int64_t more) -{ - uint64_t want = more - input_remaining(); - if ((int64_t)want <= 0) - return true; // it's already in the buffer - if (rplimit == input.limit()) - return true; // not expecting any more - - if (read_input_fn == nullptr) - { - // assume it is already all there - bytes_read += input.limit() - rplimit; - rplimit = input.limit(); - return true; - } - - uint64_t remaining = (input.limit() - rplimit); // how much left to read? - byte *rpgoal = (want >= remaining) ? input.limit() : rplimit + (size_t)want; - enum - { - CHUNK_SIZE = (1 << 14) - }; - uint64_t fetch = want; - if (fetch < CHUNK_SIZE) - fetch = CHUNK_SIZE; - if (fetch > remaining * 3 / 4) - fetch = remaining; - // Try to fetch at least "more" bytes. - while ((int64_t)fetch > 0) - { - int64_t nr = (*read_input_fn)(this, rplimit, fetch, remaining); - if (nr <= 0) - { - return (rplimit >= rpgoal); - } - remaining -= nr; - rplimit += nr; - fetch -= nr; - bytes_read += nr; - assert(remaining == (uint64_t)(input.limit() - rplimit)); - } - return true; -} - -// output handling - -fillbytes *unpacker::close_output(fillbytes *which) -{ - assert(wp != nullptr); - if (which == nullptr) - { - if (wpbase == cur_classfile_head.base()) - { - which = &cur_classfile_head; - } - else - { - which = &cur_classfile_tail; - } - } - assert(wpbase == which->base()); - assert(wplimit == which->end()); - which->setLimit(wp); - wp = nullptr; - wplimit = nullptr; - // wpbase = nullptr; - return which; -} - -// maybe_inline -void unpacker::ensure_put_space(size_t size) -{ - if (wp + size <= wplimit) - return; - // Determine which segment needs expanding. - fillbytes *which = close_output(); - byte *wp0 = which->grow(size); - wpbase = which->base(); - wplimit = which->end(); - wp = wp0; -} - -byte *unpacker::put_space(size_t size) -{ - byte *wp0 = wp; - byte *wp1 = wp0 + size; - if (wp1 > wplimit) - { - ensure_put_space(size); - wp0 = wp; - wp1 = wp0 + size; - } - wp = wp1; - return wp0; -} - -void unpacker::putu2_at(byte *wp, int n) -{ - if (n != (unsigned short)n) - { - unpack_abort(ERROR_OVERFLOW); - return; - } - wp[0] = (n) >> 8; - wp[1] = (n) >> 0; -} - -void unpacker::putu4_at(byte *wp, int n) -{ - wp[0] = (n) >> 24; - wp[1] = (n) >> 16; - wp[2] = (n) >> 8; - wp[3] = (n) >> 0; -} - -void unpacker::putu8_at(byte *wp, int64_t n) -{ - putu4_at(wp + 0, (int)((uint64_t)n >> 32)); - putu4_at(wp + 4, (int)((uint64_t)n >> 0)); -} - -void unpacker::putu2(int n) -{ - putu2_at(put_space(2), n); -} - -void unpacker::putu4(int n) -{ - putu4_at(put_space(4), n); -} - -void unpacker::putu8(int64_t n) -{ - putu8_at(put_space(8), n); -} - -int unpacker::putref_index(entry *e, int size) -{ - if (e == nullptr) - return 0; - else if (e->outputIndex > NOT_REQUESTED) - return e->outputIndex; - else if (e->tag == CONSTANT_Signature) - return putref_index(e->ref(0), size); - else - { - e->requestOutputIndex(cp, -size); - // Later on we'll fix the bits. - class_fixup_type.addByte(size); - class_fixup_offset.add((int)wpoffset()); - class_fixup_ref.add(e); - return 0; - } -} - -void unpacker::putref(entry *e) -{ - int oidx = putref_index(e, 2); - putu2_at(put_space(2), oidx); -} - -void unpacker::putu1ref(entry *e) -{ - int oidx = putref_index(e, 1); - putu1_at(put_space(1), oidx); -} - -// Allocation of small and large blocks. - -enum -{ - CHUNK = (1 << 14), - SMALL = (1 << 9) -}; - -// Call malloc. Try to combine small blocks and free much later. -void *unpacker::alloc_heap(size_t size, bool smallOK, bool temp) -{ - if (!smallOK || size > SMALL) - { - void *res = must_malloc((int)size); - (temp ? &tmallocs : &mallocs)->add(res); - return res; - } - fillbytes &xsmallbuf = *(temp ? &tsmallbuf : &smallbuf); - if (!xsmallbuf.canAppend(size + 1)) - { - xsmallbuf.init(CHUNK); - (temp ? &tmallocs : &mallocs)->add(xsmallbuf.base()); - } - int growBy = (int)size; - growBy += -growBy & 7; // round up mod 8 - return xsmallbuf.grow(growBy); -} - -void unpacker::saveTo(bytes &b, byte *ptr, size_t len) -{ - b.ptr = U_NEW(byte, add_size(len, 1)); - b.len = len; - b.copyFrom(ptr, len); -} - -// Read up through band_headers. -// Do the archive_size dance to set the size of the input mega-buffer. -void unpacker::read_file_header() -{ - // Read file header to determine file type and total size. - enum - { - MAGIC_BYTES = 4, - AH_LENGTH_0 = 3, // minver, majver, options are outside of archive_size - AH_LENGTH_0_MAX = AH_LENGTH_0 + 1, // options might have 2 bytes - AH_LENGTH = 26, // maximum archive header length (w/ all fields) - // Length contributions from optional header fields: - AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files - AH_ARCHIVE_SIZE_LEN = 2, // sizehi/lo only; part of AH_FILE_HEADER_LEN - AH_CP_NUMBER_LEN = 4, // int/float/long/double - AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers - AH_LENGTH_MIN = - AH_LENGTH - (AH_FILE_HEADER_LEN + AH_SPECIAL_FORMAT_LEN + AH_CP_NUMBER_LEN), - ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN), - FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN - }; - - assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic - assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size - // An absolute minimum nullptr archive is magic[4], {minver,majver,options}[3], - // archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes. - // (Note that archive_size is optional; it may be 0..10 bytes in length.) - // The first read must capture everything up through the options field. - // This happens to work even if {minver,majver,options} is a pathological - // 15 bytes long. Legal pack files limit those three fields to 1+1+2 bytes. - assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX); - - // Up through archive_size, the largest possible archive header is - // magic[4], {minver,majver,options}[4], archive_size[10]. - // (Note only the low 12 bits of options are allowed to be non-zero.) - // In order to parse archive_size, we need at least this many bytes - // in the first read. Of course, if archive_size_hi is more than - // a byte, we probably will fail to allocate the buffer, since it - // will be many gigabytes long. This is a practical, not an - // architectural limit to Pack200 archive sizes. - assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2 * B_MAX); - - bool foreign_buf = (read_input_fn == nullptr); - byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200]; // 200 is for JAR I/O - if (foreign_buf) - { - // inbytes is all there is - input.set(inbytes); - rp = input.base(); - rplimit = input.limit(); - } - else - { - // inbytes, if not empty, contains some read-ahead we must use first - // ensure_input will take care of copying it into initbuf, - // then querying read_input_fn for any additional data needed. - // However, the caller must assume that we use up all of inbytes. - // There is no way to tell the caller that we used only part of them. - // Therefore, the caller must use only a bare minimum of read-ahead. - if (inbytes.len > FIRST_READ) - { - unpack_abort("too much read-ahead"); - } - input.set(initbuf, sizeof(initbuf)); - input.b.clear(); - input.b.copyFrom(inbytes); - rplimit = rp = input.base(); - rplimit += inbytes.len; - bytes_read += inbytes.len; - } - // Read only 19 bytes, which is certain to contain #archive_options fields, - // but is certain not to overflow past the archive_header. - input.b.len = FIRST_READ; - if (!ensure_input(FIRST_READ)) - unpack_abort("EOF reading archive magic number"); - - if (rp[0] == 'P' && rp[1] == 'K') - { - // In the Unix-style program, we simply simulate a copy command. - // Copy until EOF; assume the JAR file is the last segment. - fprintf(stderr, "Copy-mode.\n"); - for (;;) - { - jarout->write_data(rp, (int)input_remaining()); - if (foreign_buf) - break; // one-time use of a passed in buffer - if (input.size() < CHUNK) - { - // Get some breathing room. - input.set(U_NEW(byte, (size_t)CHUNK + C_SLOP), (size_t)CHUNK); - } - rp = rplimit = input.base(); - if (!ensure_input(1)) - break; - } - jarout->closeJarFile(false); - return; - } - - // Read the magic number. - magic = 0; - for (int i1 = 0; i1 < (int)sizeof(magic); i1++) - { - magic <<= 8; - magic += (*rp++ & 0xFF); - } - - // Read the first 3 values from the header. - value_stream hdr; - int hdrVals = 0; - int hdrValsSkipped = 0; // debug only - hdr.init(rp, rplimit, UNSIGNED5_spec); - minver = hdr.getInt(); - majver = hdr.getInt(); - hdrVals += 2; - - if (magic != (int)JAVA_PACKAGE_MAGIC || - (majver != JAVA5_PACKAGE_MAJOR_VERSION && majver != JAVA6_PACKAGE_MAJOR_VERSION) || - (minver != JAVA5_PACKAGE_MINOR_VERSION && minver != JAVA6_PACKAGE_MINOR_VERSION)) - { - char message[200]; - sprintf(message, "@" ERROR_FORMAT ": magic/ver = " - "%08X/%d.%d should be %08X/%d.%d OR %08X/%d.%d\n", - magic, majver, minver, JAVA_PACKAGE_MAGIC, JAVA5_PACKAGE_MAJOR_VERSION, - JAVA5_PACKAGE_MINOR_VERSION, JAVA_PACKAGE_MAGIC, JAVA6_PACKAGE_MAJOR_VERSION, - JAVA6_PACKAGE_MINOR_VERSION); - unpack_abort(message); - } - - archive_options = hdr.getInt(); - hdrVals += 1; - assert(hdrVals == AH_LENGTH_0); // first three fields only - -#define ORBIT(bit) | (bit) - int OPTION_LIMIT = (0 ARCHIVE_BIT_DO(ORBIT)); -#undef ORBIT - if ((archive_options & ~OPTION_LIMIT) != 0) - { - fprintf(stderr, "Warning: Illegal archive options 0x%x\n", archive_options); - unpack_abort("illegal archive options"); - return; - } - - if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) - { - uint32_t hi = hdr.getInt(); - uint32_t lo = hdr.getInt(); - uint64_t x = band::makeLong(hi, lo); - archive_size = (size_t)x; - if (archive_size != x) - { - // Silly size specified; force overflow. - archive_size = PSIZE_MAX + 1; - } - hdrVals += 2; - } - else - { - hdrValsSkipped += 2; - } - - // Now we can size the whole archive. - // Read everything else into a mega-buffer. - rp = hdr.rp; - int header_size_0 = (int)(rp - input.base()); // used-up header (4byte + 3int) - int header_size_1 = (int)(rplimit - rp); // buffered unused initial fragment - int header_size = header_size_0 + header_size_1; - unsized_bytes_read = header_size_0; - if (foreign_buf) - { - if (archive_size > (size_t)header_size_1) - { - unpack_abort("EOF reading fixed input buffer"); - return; - } - } - else if (archive_size != 0) - { - if (archive_size < ARCHIVE_SIZE_MIN) - { - unpack_abort("impossible archive size"); // bad input data - return; - } - if (archive_size < (size_t)header_size_1) - { - unpack_abort("too much read-ahead"); // somehow we pre-fetched too much? - return; - } - input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)), - (size_t)header_size_0 + archive_size); - assert(input.limit()[0] == 0); - // Move all the bytes we read initially into the real buffer. - input.b.copyFrom(initbuf, header_size); - rp = input.b.ptr + header_size_0; - rplimit = input.b.ptr + header_size; - } - else - { - // It's more complicated and painful. - // A zero archive_size means that we must read until EOF. - input.init(CHUNK * 2); - input.b.len = input.allocated; - rp = rplimit = input.base(); - // Set up input buffer as if we already read the header: - input.b.copyFrom(initbuf, header_size); - rplimit += header_size; - while (ensure_input(input.limit() - rp)) - { - size_t dataSoFar = input_remaining(); - size_t nextSize = add_size(dataSoFar, CHUNK); - input.ensureSize(nextSize); - input.b.len = input.allocated; - rp = rplimit = input.base(); - rplimit += dataSoFar; - } - size_t dataSize = (rplimit - input.base()); - input.b.len = dataSize; - input.grow(C_SLOP); - free_input = true; // free it later - input.b.len = dataSize; - assert(input.limit()[0] == 0); - rp = rplimit = input.base(); - rplimit += dataSize; - rp += header_size_0; // already scanned these bytes... - } - live_input = true; // mark as "do not reuse" - - // read the rest of the header fields - ensure_input((AH_LENGTH - AH_LENGTH_0) * B_MAX); - hdr.rp = rp; - hdr.rplimit = rplimit; - - if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) - { - archive_next_count = hdr.getInt(); - if (archive_next_count < 0) - unpack_abort("bad archive_next_count"); - archive_modtime = hdr.getInt(); - file_count = hdr.getInt(); - if (file_count < 0) - unpack_abort("bad file_count"); - hdrVals += 3; - } - else - { - hdrValsSkipped += 3; - } - - if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) - { - band_headers_size = hdr.getInt(); - if (band_headers_size < 0) - unpack_abort("bad band_headers_size"); - attr_definition_count = hdr.getInt(); - if (attr_definition_count < 0) - unpack_abort("bad attr_definition_count"); - hdrVals += 2; - } - else - { - hdrValsSkipped += 2; - } - - int cp_counts[N_TAGS_IN_ORDER]; - for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) - { - if (!(archive_options & AO_HAVE_CP_NUMBERS)) - { - switch (TAGS_IN_ORDER[k]) - { - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Long: - case CONSTANT_Double: - cp_counts[k] = 0; - hdrValsSkipped += 1; - continue; - } - } - cp_counts[k] = hdr.getInt(); - if (cp_counts[k] < 0) - unpack_abort("bad cp_counts"); - hdrVals += 1; - } - - ic_count = hdr.getInt(); - if (ic_count < 0) - unpack_abort("bad ic_count"); - - default_class_minver = hdr.getInt(); - default_class_majver = hdr.getInt(); - - class_count = hdr.getInt(); - if (class_count < 0) - unpack_abort("bad class_count"); - - hdrVals += 4; - - // done with archive_header - hdrVals += hdrValsSkipped; - assert(hdrVals == AH_LENGTH); - - rp = hdr.rp; - if (rp > rplimit) - unpack_abort("EOF reading archive header"); - - // Now size the CP. - cp.init(this, cp_counts); - - default_file_modtime = archive_modtime; - if (default_file_modtime == 0 && !(archive_options & AO_HAVE_FILE_MODTIME)) - default_file_modtime = DEFAULT_ARCHIVE_MODTIME; // taken from driver - if ((archive_options & AO_DEFLATE_HINT) != 0) - default_file_options |= FO_DEFLATE_HINT; - - // meta-bytes, if any, immediately follow archive header - // band_headers.readData(band_headers_size); - ensure_input(band_headers_size); - if (input_remaining() < (size_t)band_headers_size) - { - unpack_abort("EOF reading band headers"); - return; - } - bytes band_headers; - // The "1+" allows an initial byte to be pushed on the front. - band_headers.set(1 + U_NEW(byte, 1 + band_headers_size + C_SLOP), band_headers_size); - - // Start scanning band headers here: - band_headers.copyFrom(rp, band_headers.len); - rp += band_headers.len; - assert(rp <= rplimit); - meta_rp = band_headers.ptr; - // Put evil meta-codes at the end of the band headers, - // so we are sure to throw an error if we run off the end. - bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error); -} - -void unpacker::finish() -{ - if (verbose >= 1) - { - fprintf(stderr, "A total of %" PRIu64 " bytes were read in %d segment(s).\n", - (bytes_read_before_reset + bytes_read), segments_read_before_reset + 1); - fprintf(stderr, "A total of %" PRIu64 " file content bytes were written.\n", - (bytes_written_before_reset + bytes_written)); - fprintf(stderr, - "A total of %d files (of which %d are classes) were written to output.\n", - files_written_before_reset + files_written, - classes_written_before_reset + classes_written); - } - if (jarout != nullptr) - jarout->closeJarFile(true); -} - -// Cf. PackageReader.readConstantPoolCounts -void constant_pool::init(unpacker *u_, int counts[NUM_COUNTS]) -{ - this->u = u_; - - // Fill-pointer for CP. - int next_entry = 0; - - // Size the constant pool: - for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) - { - byte tag = TAGS_IN_ORDER[k]; - int len = counts[k]; - tag_count[tag] = len; - tag_base[tag] = next_entry; - next_entry += len; - // Detect and defend against constant pool size overflow. - // (Pack200 forbids the sum of CP counts to exceed 2^29-1.) - enum - { - CP_SIZE_LIMIT = (1 << 29), - IMPLICIT_ENTRY_COUNT = 1 // empty Utf8 string - }; - if (len >= (1 << 29) || len < 0 || next_entry >= CP_SIZE_LIMIT + IMPLICIT_ENTRY_COUNT) - { - unpack_abort("archive too large: constant pool limit exceeded"); - } - } - - // Close off the end of the CP: - nentries = next_entry; - - // place a limit on future CP growth: - int generous = 0; - generous = add_size(generous, u->ic_count); // implicit name - generous = add_size(generous, u->ic_count); // outer - generous = add_size(generous, u->ic_count); // outer.utf8 - generous = add_size(generous, 40); // WKUs, misc - generous = add_size(generous, u->class_count); // implicit SourceFile strings - maxentries = add_size(nentries, generous); - - // Note that this CP does not include "empty" entries - // for longs and doubles. Those are introduced when - // the entries are renumbered for classfile output. - - entries = U_NEW(entry, maxentries); - - first_extra_entry = &entries[nentries]; - - // Initialize the standard indexes. - tag_count[CONSTANT_All] = nentries; - tag_base[CONSTANT_All] = 0; - for (int tag = 0; tag < CONSTANT_Limit; tag++) - { - entry *cpMap = &entries[tag_base[tag]]; - tag_index[tag].init(tag_count[tag], cpMap, tag); - } - - // Initialize hashTab to a generous power-of-two size. - uint32_t pow2 = 1; - uint32_t target = maxentries + maxentries / 2; // 60% full - while (pow2 < target) - pow2 <<= 1; - hashTab = U_NEW(entry *, hashTabLength = pow2); -} - -static byte *store_Utf8_char(byte *cp, unsigned short ch) -{ - if (ch >= 0x001 && ch <= 0x007F) - { - *cp++ = (byte)ch; - } - else if (ch <= 0x07FF) - { - *cp++ = (byte)(0xC0 | ((ch >> 6) & 0x1F)); - *cp++ = (byte)(0x80 | ((ch >> 0) & 0x3F)); - } - else - { - *cp++ = (byte)(0xE0 | ((ch >> 12) & 0x0F)); - *cp++ = (byte)(0x80 | ((ch >> 6) & 0x3F)); - *cp++ = (byte)(0x80 | ((ch >> 0) & 0x3F)); - } - return cp; -} - -static byte *skip_Utf8_chars(byte *cp, int len) -{ - for (;; cp++) - { - int ch = *cp & 0xFF; - if ((ch & 0xC0) != 0x80) - { - if (len-- == 0) - return cp; - if (ch < 0x80 && len == 0) - return cp + 1; - } - } -} - -static int compare_Utf8_chars(bytes &b1, bytes &b2) -{ - int l1 = (int)b1.len; - int l2 = (int)b2.len; - int l0 = (l1 < l2) ? l1 : l2; - byte *p1 = b1.ptr; - byte *p2 = b2.ptr; - int c0 = 0; - for (int i = 0; i < l0; i++) - { - int c1 = p1[i] & 0xFF; - int c2 = p2[i] & 0xFF; - if (c1 != c2) - { - // Before returning the obvious answer, - // check to see if c1 or c2 is part of a 0x0000, - // which encodes as {0xC0,0x80}. The 0x0000 is the - // lowest-sorting Java char value, and yet it encodes - // as if it were the first char after 0x7F, which causes - // strings containing nulls to sort too high. All other - // comparisons are consistent between Utf8 and Java chars. - if (c1 == 0xC0 && (p1[i + 1] & 0xFF) == 0x80) - c1 = 0; - if (c2 == 0xC0 && (p2[i + 1] & 0xFF) == 0x80) - c2 = 0; - if (c0 == 0xC0) - { - assert(((c1 | c2) & 0xC0) == 0x80); // c1 & c2 are extension chars - if (c1 == 0x80) - c1 = 0; // will sort below c2 - if (c2 == 0x80) - c2 = 0; // will sort below c1 - } - return c1 - c2; - } - c0 = c1; // save away previous char - } - // common prefix is identical; return length difference if any - return l1 - l2; -} - -// Cf. PackageReader.readUtf8Bands -void unpacker::read_Utf8_values(entry *cpMap, int len) -{ - // Implicit first Utf8 string is the empty string. - enum - { - // certain bands begin with implicit zeroes - PREFIX_SKIP_2 = 2, - SUFFIX_SKIP_1 = 1 - }; - - int i; - - // First band: Read lengths of shared prefixes. - if (len > PREFIX_SKIP_2) - cp_Utf8_prefix.readData(len - PREFIX_SKIP_2); - - // Second band: Read lengths of unshared suffixes: - if (len > SUFFIX_SKIP_1) - cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1); - - bytes *allsuffixes = T_NEW(bytes, len); - - int nbigsuf = 0; - fillbytes charbuf; // buffer to allocate small strings - charbuf.init(); - - // Third band: Read the char values in the unshared suffixes: - cp_Utf8_chars.readData(cp_Utf8_suffix.getIntTotal()); - for (i = 0; i < len; i++) - { - int suffix = (i < SUFFIX_SKIP_1) ? 0 : cp_Utf8_suffix.getInt(); - if (suffix < 0) - { - unpack_abort("bad utf8 suffix"); - } - if (suffix == 0 && i >= SUFFIX_SKIP_1) - { - // chars are packed in cp_Utf8_big_chars - nbigsuf += 1; - continue; - } - bytes &chars = allsuffixes[i]; - uint32_t size3 = suffix * 3; // max Utf8 length - bool isMalloc = (suffix > SMALL); - if (isMalloc) - { - chars.malloc(size3); - } - else - { - if (!charbuf.canAppend(size3 + 1)) - { - assert(charbuf.allocated == 0 || tmallocs.contains(charbuf.base())); - charbuf.init(CHUNK); // Reset to new buffer. - tmallocs.add(charbuf.base()); - } - chars.set(charbuf.grow(size3 + 1), size3); - } - - byte *chp = chars.ptr; - for (int j = 0; j < suffix; j++) - { - unsigned short ch = cp_Utf8_chars.getInt(); - chp = store_Utf8_char(chp, ch); - } - // shrink to fit: - if (isMalloc) - { - chars.realloc(chp - chars.ptr); - tmallocs.add(chars.ptr); // free it later - } - else - { - int shrink = (int)(chars.limit() - chp); - chars.len -= shrink; - charbuf.b.len -= shrink; // ungrow to reclaim buffer space - // Note that we did not reclaim the final '\0'. - assert(chars.limit() == charbuf.limit() - 1); - assert(strlen((char *)chars.ptr) == chars.len); - } - } - // cp_Utf8_chars.done(); - - // Fourth band: Go back and size the specially packed strings. - int maxlen = 0; - cp_Utf8_big_suffix.readData(nbigsuf); - cp_Utf8_suffix.rewind(); - for (i = 0; i < len; i++) - { - int suffix = (i < SUFFIX_SKIP_1) ? 0 : cp_Utf8_suffix.getInt(); - int prefix = (i < PREFIX_SKIP_2) ? 0 : cp_Utf8_prefix.getInt(); - if (prefix < 0 || prefix + suffix < 0) - { - unpack_abort("bad utf8 prefix"); - } - bytes &chars = allsuffixes[i]; - if (suffix == 0 && i >= SUFFIX_SKIP_1) - { - suffix = cp_Utf8_big_suffix.getInt(); - assert(chars.ptr == nullptr); - chars.len = suffix; // just a momentary hack - } - else - { - assert(chars.ptr != nullptr); - } - if (maxlen < prefix + suffix) - { - maxlen = prefix + suffix; - } - } - // cp_Utf8_suffix.done(); // will use allsuffixes[i].len (ptr!=nullptr) - // cp_Utf8_big_suffix.done(); // will use allsuffixes[i].len - - // Fifth band(s): Get the specially packed characters. - cp_Utf8_big_suffix.rewind(); - for (i = 0; i < len; i++) - { - bytes &chars = allsuffixes[i]; - if (chars.ptr != nullptr) - continue; // already input - int suffix = (int)chars.len; // pick up the hack - uint32_t size3 = suffix * 3; - if (suffix == 0) - continue; // done with empty string - chars.malloc(size3); - byte *chp = chars.ptr; - band saved_band = cp_Utf8_big_chars; - cp_Utf8_big_chars.readData(suffix); - for (int j = 0; j < suffix; j++) - { - unsigned short ch = cp_Utf8_big_chars.getInt(); - chp = store_Utf8_char(chp, ch); - } - chars.realloc(chp - chars.ptr); - tmallocs.add(chars.ptr); // free it later - // cp_Utf8_big_chars.done(); - cp_Utf8_big_chars = saved_band; // reset the band for the next string - } - cp_Utf8_big_chars.readData(0); // zero chars - // cp_Utf8_big_chars.done(); - - // Finally, sew together all the prefixes and suffixes. - bytes bigbuf; - bigbuf.malloc(maxlen * 3 + 1); // max Utf8 length, plus slop for nullptr - int prevlen = 0; // previous string length (in chars) - tmallocs.add(bigbuf.ptr); // free after this block - cp_Utf8_prefix.rewind(); - for (i = 0; i < len; i++) - { - bytes &chars = allsuffixes[i]; - int prefix = (i < PREFIX_SKIP_2) ? 0 : cp_Utf8_prefix.getInt(); - int suffix = (int)chars.len; - byte *fillp; - // by induction, the buffer is already filled with the prefix - // make sure the prefix value is not corrupted, though: - if (prefix > prevlen) - { - unpack_abort("utf8 prefix overflow"); - return; - } - fillp = skip_Utf8_chars(bigbuf.ptr, prefix); - // copy the suffix into the same buffer: - fillp = chars.writeTo(fillp); - assert(bigbuf.inBounds(fillp)); - *fillp = 0; // bigbuf must contain a well-formed Utf8 string - int length = (int)(fillp - bigbuf.ptr); - bytes &value = cpMap[i].value.b; - value.set(U_NEW(byte, add_size(length, 1)), length); - value.copyFrom(bigbuf.ptr, length); - // Index all Utf8 strings - entry *&htref = cp.hashTabRef(CONSTANT_Utf8, value); - if (htref == nullptr) - { - // Note that if two identical strings are transmitted, - // the first is taken to be the canonical one. - htref = &cpMap[i]; - } - prevlen = prefix + suffix; - } - // cp_Utf8_prefix.done(); - - // Free intermediate buffers. - free_temps(); -} - -void unpacker::read_single_words(band &cp_band, entry *cpMap, int len) -{ - cp_band.readData(len); - for (int i = 0; i < len; i++) - { - cpMap[i].value.i = cp_band.getInt(); // coding handles signs OK - } -} - -void unpacker::read_double_words(band &cp_bands, entry *cpMap, int len) -{ - band &cp_band_hi = cp_bands; - band &cp_band_lo = cp_bands.nextBand(); - cp_band_hi.readData(len); - cp_band_lo.readData(len); - for (int i = 0; i < len; i++) - { - cpMap[i].value.l = cp_band_hi.getLong(cp_band_lo, true); - } - // cp_band_hi.done(); - // cp_band_lo.done(); -} - -void unpacker::read_single_refs(band &cp_band, byte refTag, entry *cpMap, int len) -{ - assert(refTag == CONSTANT_Utf8); - cp_band.setIndexByTag(refTag); - cp_band.readData(len); - int indexTag = (cp_band.bn == e_cp_Class) ? CONSTANT_Class : 0; - for (int i = 0; i < len; i++) - { - entry &e = cpMap[i]; - e.refs = U_NEW(entry *, e.nrefs = 1); - entry *utf = cp_band.getRef(); - e.refs[0] = utf; - e.value.b = utf->value.b; // copy value of Utf8 string to self - if (indexTag != 0) - { - // Maintain cross-reference: - entry *&htref = cp.hashTabRef(indexTag, e.value.b); - if (htref == nullptr) - { - // Note that if two identical classes are transmitted, - // the first is taken to be the canonical one. - htref = &e; - } - } - } - // cp_band.done(); -} - -void unpacker::read_double_refs(band &cp_band, byte ref1Tag, byte ref2Tag, entry *cpMap, - int len) -{ - band &cp_band1 = cp_band; - band &cp_band2 = cp_band.nextBand(); - cp_band1.setIndexByTag(ref1Tag); - cp_band2.setIndexByTag(ref2Tag); - cp_band1.readData(len); - cp_band2.readData(len); - for (int i = 0; i < len; i++) - { - entry &e = cpMap[i]; - e.refs = U_NEW(entry *, e.nrefs = 2); - e.refs[0] = cp_band1.getRef(); - e.refs[1] = cp_band2.getRef(); - } - // cp_band1.done(); - // cp_band2.done(); -} - -// Cf. PackageReader.readSignatureBands -void unpacker::read_signature_values(entry *cpMap, int len) -{ - cp_Signature_form.setIndexByTag(CONSTANT_Utf8); - cp_Signature_form.readData(len); - int ncTotal = 0; - int i; - for (i = 0; i < len; i++) - { - entry &e = cpMap[i]; - entry &form = *cp_Signature_form.getRef(); - int nc = 0; - - for (const char *ncp = form.utf8String(); *ncp; ncp++) - { - if (*ncp == 'L') - nc++; - } - - ncTotal += nc; - e.refs = U_NEW(entry *, cpMap[i].nrefs = 1 + nc); - e.refs[0] = &form; - } - // cp_Signature_form.done(); - cp_Signature_classes.setIndexByTag(CONSTANT_Class); - cp_Signature_classes.readData(ncTotal); - for (i = 0; i < len; i++) - { - entry &e = cpMap[i]; - for (int j = 1; j < e.nrefs; j++) - { - e.refs[j] = cp_Signature_classes.getRef(); - } - } - // cp_Signature_classes.done(); -} - -// Cf. PackageReader.readConstantPool -void unpacker::read_cp() -{ - int i; - - for (int k = 0; k < (int)N_TAGS_IN_ORDER; k++) - { - byte tag = TAGS_IN_ORDER[k]; - int len = cp.tag_count[tag]; - int base = cp.tag_base[tag]; - - entry *cpMap = &cp.entries[base]; - for (i = 0; i < len; i++) - { - cpMap[i].tag = tag; - cpMap[i].inord = i; - } - - switch (tag) - { - case CONSTANT_Utf8: - read_Utf8_values(cpMap, len); - break; - case CONSTANT_Integer: - read_single_words(cp_Int, cpMap, len); - break; - case CONSTANT_Float: - read_single_words(cp_Float, cpMap, len); - break; - case CONSTANT_Long: - read_double_words(cp_Long_hi /*& cp_Long_lo*/, cpMap, len); - break; - case CONSTANT_Double: - read_double_words(cp_Double_hi /*& cp_Double_lo*/, cpMap, len); - break; - case CONSTANT_String: - read_single_refs(cp_String, CONSTANT_Utf8, cpMap, len); - break; - case CONSTANT_Class: - read_single_refs(cp_Class, CONSTANT_Utf8, cpMap, len); - break; - case CONSTANT_Signature: - read_signature_values(cpMap, len); - break; - case CONSTANT_NameandType: - read_double_refs(cp_Descr_name /*& cp_Descr_type*/, CONSTANT_Utf8, - CONSTANT_Signature, cpMap, len); - break; - case CONSTANT_Fieldref: - read_double_refs(cp_Field_class /*& cp_Field_desc*/, CONSTANT_Class, - CONSTANT_NameandType, cpMap, len); - break; - case CONSTANT_Methodref: - read_double_refs(cp_Method_class /*& cp_Method_desc*/, CONSTANT_Class, - CONSTANT_NameandType, cpMap, len); - break; - case CONSTANT_InterfaceMethodref: - read_double_refs(cp_Imethod_class /*& cp_Imethod_desc*/, CONSTANT_Class, - CONSTANT_NameandType, cpMap, len); - break; - default: - assert(false); - break; - } - } - - cp.expandSignatures(); - cp.initMemberIndexes(); - -#define SNAME(n, s) #s "\0" - const char *symNames = (ALL_ATTR_DO(SNAME) ""); -#undef SNAME - - for (int sn = 0; sn < constant_pool::s_LIMIT; sn++) - { - assert(symNames[0] >= '0' && symNames[0] <= 'Z'); // sanity - bytes name; - name.set(symNames); - if (name.len > 0 && name.ptr[0] != '0') - { - cp.sym[sn] = cp.ensureUtf8(name); - } - symNames += name.len + 1; // skip trailing nullptr to next name - } - - band::initIndexes(this); -} - -static band *no_bands[] = {nullptr}; // shared empty body - -inline band &unpacker::attr_definitions::fixed_band(int e_class_xxx) -{ - return u->all_bands[xxx_flags_hi_bn + (e_class_xxx - e_class_flags_hi)]; -} -inline band &unpacker::attr_definitions::xxx_flags_hi() -{ - return fixed_band(e_class_flags_hi); -} -inline band &unpacker::attr_definitions::xxx_flags_lo() -{ - return fixed_band(e_class_flags_lo); -} -inline band &unpacker::attr_definitions::xxx_attr_count() -{ - return fixed_band(e_class_attr_count); -} -inline band &unpacker::attr_definitions::xxx_attr_indexes() -{ - return fixed_band(e_class_attr_indexes); -} -inline band &unpacker::attr_definitions::xxx_attr_calls() -{ - return fixed_band(e_class_attr_calls); -} - -inline unpacker::layout_definition * -unpacker::attr_definitions::defineLayout(int idx, entry *nameEntry, const char *layout) -{ - const char *name = nameEntry->value.b.strval(); - layout_definition *lo = defineLayout(idx, name, layout); - lo->nameEntry = nameEntry; - return lo; -} - -unpacker::layout_definition *unpacker::attr_definitions::defineLayout(int idx, const char *name, - const char *layout) -{ - assert(flag_limit != 0); // must be set up already - if (idx >= 0) - { - // Fixed attr. - if (idx >= (int)flag_limit) - unpack_abort("attribute index too large"); - if (isRedefined(idx)) - unpack_abort("redefined attribute index"); - redef |= ((uint64_t)1 << idx); - } - else - { - idx = flag_limit + overflow_count.length(); - overflow_count.add(0); // make a new counter - } - layout_definition *lo = U_NEW(layout_definition, 1); - lo->idx = idx; - lo->name = name; - lo->layout = layout; - for (int adds = (idx + 1) - layouts.length(); adds > 0; adds--) - { - layouts.add(nullptr); - } - layouts.get(idx) = lo; - return lo; -} - -band **unpacker::attr_definitions::buildBands(unpacker::layout_definition *lo) -{ - int i; - if (lo->elems != nullptr) - return lo->bands(); - if (lo->layout[0] == '\0') - { - lo->elems = no_bands; - } - else - { - // Create bands for this attribute by parsing the layout. - bool hasCallables = lo->hasCallables(); - bands_made = 0x10000; // base number for bands made - const char *lp = lo->layout; - lp = parseLayout(lp, lo->elems, -1); - if (lp[0] != '\0' || band_stack.length() > 0) - { - unpack_abort("garbage at end of layout"); - } - band_stack.popTo(0); - - // Fix up callables to point at their callees. - band **bands = lo->elems; - assert(bands == lo->bands()); - int num_callables = 0; - if (hasCallables) - { - while (bands[num_callables] != nullptr) - { - if (bands[num_callables]->le_kind != EK_CBLE) - { - unpack_abort("garbage mixed with callables"); - break; - } - num_callables += 1; - } - } - for (i = 0; i < calls_to_link.length(); i++) - { - band &call = *(band *)calls_to_link.get(i); - assert(call.le_kind == EK_CALL); - // Determine the callee. - int call_num = call.le_len; - if (call_num < 0 || call_num >= num_callables) - { - unpack_abort("bad call in layout"); - break; - } - band &cble = *bands[call_num]; - // Link the call to it. - call.le_body[0] = &cble; - // Distinguish backward calls and callables: - assert(cble.le_kind == EK_CBLE); - // FIXME: hit this one - // assert(cble.le_len == call_num); - cble.le_back |= call.le_back; - } - calls_to_link.popTo(0); - } - return lo->elems; -} - -/* attribute layout language parser - - attribute_layout: - ( layout_element )* | ( callable )+ - layout_element: - ( integral | replication | union | call | reference ) - - callable: - '[' body ']' - body: - ( layout_element )+ - - integral: - ( unsigned_int | signed_int | bc_index | bc_offset | flag ) - unsigned_int: - uint_type - signed_int: - 'S' uint_type - any_int: - ( unsigned_int | signed_int ) - bc_index: - ( 'P' uint_type | 'PO' uint_type ) - bc_offset: - 'O' any_int - flag: - 'F' uint_type - uint_type: - ( 'B' | 'H' | 'I' | 'V' ) - - replication: - 'N' uint_type '[' body ']' - - union: - 'T' any_int (union_case)* '(' ')' '[' (body)? ']' - union_case: - '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']' - union_case_tag: - ( numeral | numeral '-' numeral ) - call: - '(' numeral ')' - - reference: - reference_type ( 'N' )? uint_type - reference_type: - ( constant_ref | schema_ref | utf8_ref | untyped_ref ) - constant_ref: - ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' ) - schema_ref: - ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' ) - utf8_ref: - 'RU' - untyped_ref: - 'RQ' - - numeral: - '(' ('-')? (digit)+ ')' - digit: - ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) - -*/ - -const char *unpacker::attr_definitions::parseIntLayout(const char *lp, band *&res, byte le_kind, - bool can_be_signed) -{ - band *b = U_NEW(band, 1); - char le = *lp++; - int spec = UNSIGNED5_spec; - if (le == 'S' && can_be_signed) - { - // Note: This is the last use of sign. There is no 'EF_SIGN'. - spec = SIGNED5_spec; - le = *lp++; - } - else if (le == 'B') - { - spec = BYTE1_spec; // unsigned byte - } - b->init(u, bands_made++, spec); - b->le_kind = le_kind; - int le_len = 0; - switch (le) - { - case 'B': - le_len = 1; - break; - case 'H': - le_len = 2; - break; - case 'I': - le_len = 4; - break; - case 'V': - le_len = 0; - break; - default: - unpack_abort("bad layout element"); - } - b->le_len = le_len; - band_stack.add(b); - res = b; - return lp; -} - -const char *unpacker::attr_definitions::parseNumeral(const char *lp, int &res) -{ - bool sgn = false; - if (*lp == '0') - { - res = 0; - return lp + 1; - } // special case '0' - if (*lp == '-') - { - sgn = true; - lp++; - } - const char *dp = lp; - int con = 0; - while (*dp >= '0' && *dp <= '9') - { - int con0 = con; - con *= 10; - con += (*dp++) - '0'; - if (con <= con0) - { - con = -1; - break; - } // numeral overflow - } - if (lp == dp) - { - unpack_abort("missing numeral in layout"); - } - lp = dp; - if (con < 0 && !(sgn && con == -con)) - { - // (Portability note: Misses the error if int is not 32 bits.) - unpack_abort("numeral overflow"); - } - if (sgn) - con = -con; - res = con; - return lp; -} - -band **unpacker::attr_definitions::popBody(int bs_base) -{ - // Return everything that was pushed, as a nullptr-terminated pointer array. - int bs_limit = band_stack.length(); - if (bs_base == bs_limit) - { - return no_bands; - } - else - { - int nb = bs_limit - bs_base; - band **res = U_NEW(band *, add_size(nb, 1)); - for (int i = 0; i < nb; i++) - { - band *b = (band *)band_stack.get(bs_base + i); - res[i] = b; - } - band_stack.popTo(bs_base); - return res; - } -} - -const char *unpacker::attr_definitions::parseLayout(const char *lp, band **&res, int curCble) -{ - int bs_base = band_stack.length(); - bool top_level = (bs_base == 0); - band *b; - enum - { - can_be_signed = true - }; // optional arg to parseIntLayout - - for (bool done = false; !done;) - { - switch (*lp++) - { - case 'B': - case 'H': - case 'I': - case 'V': // unsigned_int - case 'S': // signed_int - --lp; // reparse - case 'F': - lp = parseIntLayout(lp, b, EK_INT); - break; - case 'P': - { - int le_bci = EK_BCI; - if (*lp == 'O') - { - ++lp; - le_bci = EK_BCID; - } - assert(*lp != 'S'); // no PSH, etc. - lp = parseIntLayout(lp, b, EK_INT); - b->le_bci = le_bci; - if (le_bci == EK_BCI) - b->defc = coding::findBySpec(BCI5_spec); - else - b->defc = coding::findBySpec(BRANCH5_spec); - } - break; - case 'O': - lp = parseIntLayout(lp, b, EK_INT, can_be_signed); - b->le_bci = EK_BCO; - b->defc = coding::findBySpec(BRANCH5_spec); - break; - case 'N': // replication: 'N' uint32_t '[' elem ... ']' - lp = parseIntLayout(lp, b, EK_REPL); - assert(*lp == '['); - ++lp; - lp = parseLayout(lp, b->le_body, curCble); - break; - case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' - lp = parseIntLayout(lp, b, EK_UN, can_be_signed); - { - int union_base = band_stack.length(); - for (;;) - { // for each case - band &k_case = *U_NEW(band, 1); - band_stack.add(&k_case); - k_case.le_kind = EK_CASE; - k_case.bn = bands_made++; - if (*lp++ != '(') - { - unpack_abort("bad union case"); - return ""; - } - if (*lp++ != ')') - { - --lp; // reparse - // Read some case values. (Use band_stack for temp. storage.) - int case_base = band_stack.length(); - for (;;) - { - int caseval = 0; - lp = parseNumeral(lp, caseval); - band_stack.add((void *)(size_t)caseval); - if (*lp == '-') - { - // new in version 160, allow (1-5) for (1,2,3,4,5) - if (u->majver < JAVA6_PACKAGE_MAJOR_VERSION) - { - unpack_abort( - "bad range in union case label (old archive format)"); - return ""; - } - int caselimit = caseval; - lp++; - lp = parseNumeral(lp, caselimit); - if (caseval >= caselimit || - (uint32_t)(caselimit - caseval) > 0x10000) - { - // Note: 0x10000 is arbitrary implementation restriction. - // We can remove it later if it's important to. - unpack_abort("bad range in union case label"); - } - for (;;) - { - ++caseval; - band_stack.add((void *)(size_t)caseval); - if (caseval == caselimit) - break; - } - } - if (*lp != ',') - break; - lp++; - } - if (*lp++ != ')') - { - unpack_abort("bad case label"); - } - // save away the case labels - int ntags = band_stack.length() - case_base; - int *tags = U_NEW(int, add_size(ntags, 1)); - k_case.le_casetags = tags; - *tags++ = ntags; - for (int i = 0; i < ntags; i++) - { - *tags++ = ptrlowbits(band_stack.get(case_base + i)); - } - band_stack.popTo(case_base); - } - // Got le_casetags. Now grab the body. - assert(*lp == '['); - ++lp; - lp = parseLayout(lp, k_case.le_body, curCble); - if (k_case.le_casetags == nullptr) - break; // done - } - b->le_body = popBody(union_base); - } - break; - case '(': // call: '(' -?NN* ')' - { - band &call = *U_NEW(band, 1); - band_stack.add(&call); - call.le_kind = EK_CALL; - call.bn = bands_made++; - call.le_body = U_NEW(band *, 2); // fill in later - int call_num = 0; - lp = parseNumeral(lp, call_num); - call.le_back = (call_num <= 0); - call_num += curCble; // numeral is self-relative offset - call.le_len = call_num; // use le_len as scratch - calls_to_link.add(&call); - if (*lp++ != ')') - { - unpack_abort("bad call label"); - } - } - break; - case 'K': // reference_type: constant_ref - case 'R': // reference_type: schema_ref - { - int ixTag = CONSTANT_None; - if (lp[-1] == 'K') - { - switch (*lp++) - { - case 'I': - ixTag = CONSTANT_Integer; - break; - case 'J': - ixTag = CONSTANT_Long; - break; - case 'F': - ixTag = CONSTANT_Float; - break; - case 'D': - ixTag = CONSTANT_Double; - break; - case 'S': - ixTag = CONSTANT_String; - break; - case 'Q': - ixTag = CONSTANT_Literal; - break; - } - } - else - { - switch (*lp++) - { - case 'C': - ixTag = CONSTANT_Class; - break; - case 'S': - ixTag = CONSTANT_Signature; - break; - case 'D': - ixTag = CONSTANT_NameandType; - break; - case 'F': - ixTag = CONSTANT_Fieldref; - break; - case 'M': - ixTag = CONSTANT_Methodref; - break; - case 'I': - ixTag = CONSTANT_InterfaceMethodref; - break; - case 'U': - ixTag = CONSTANT_Utf8; - break; // utf8_ref - case 'Q': - ixTag = CONSTANT_All; - break; // untyped_ref - } - } - if (ixTag == CONSTANT_None) - { - unpack_abort("bad reference layout"); - break; - } - bool nullOK = false; - if (*lp == 'N') - { - nullOK = true; - lp++; - } - lp = parseIntLayout(lp, b, EK_REF); - b->defc = coding::findBySpec(UNSIGNED5_spec); - b->initRef(ixTag, nullOK); - } - break; - case '[': - { - // [callable1][callable2]... - if (!top_level) - { - unpack_abort("bad nested callable"); - break; - } - curCble += 1; - band &cble = *U_NEW(band, 1); - band_stack.add(&cble); - cble.le_kind = EK_CBLE; - cble.bn = bands_made++; - lp = parseLayout(lp, cble.le_body, curCble); - } - break; - case ']': - // Hit a closing brace. This ends whatever body we were in. - done = true; - break; - case '\0': - // Hit a nullptr. Also ends the (top-level) body. - --lp; // back up, so caller can see the nullptr also - done = true; - break; - default: - unpack_abort("bad layout"); - } - } - - // Return the accumulated bands: - res = popBody(bs_base); - return lp; -} - -void unpacker::read_attr_defs() -{ - int i; - - // Tell each AD which attrc it is and where its fixed flags are: - attr_defs[ATTR_CONTEXT_CLASS].attrc = ATTR_CONTEXT_CLASS; - attr_defs[ATTR_CONTEXT_CLASS].xxx_flags_hi_bn = e_class_flags_hi; - attr_defs[ATTR_CONTEXT_FIELD].attrc = ATTR_CONTEXT_FIELD; - attr_defs[ATTR_CONTEXT_FIELD].xxx_flags_hi_bn = e_field_flags_hi; - attr_defs[ATTR_CONTEXT_METHOD].attrc = ATTR_CONTEXT_METHOD; - attr_defs[ATTR_CONTEXT_METHOD].xxx_flags_hi_bn = e_method_flags_hi; - attr_defs[ATTR_CONTEXT_CODE].attrc = ATTR_CONTEXT_CODE; - attr_defs[ATTR_CONTEXT_CODE].xxx_flags_hi_bn = e_code_flags_hi; - - // Decide whether bands for the optional high flag words are present. - attr_defs[ATTR_CONTEXT_CLASS] - .setHaveLongFlags((archive_options & AO_HAVE_CLASS_FLAGS_HI) != 0); - attr_defs[ATTR_CONTEXT_FIELD] - .setHaveLongFlags((archive_options & AO_HAVE_FIELD_FLAGS_HI) != 0); - attr_defs[ATTR_CONTEXT_METHOD] - .setHaveLongFlags((archive_options & AO_HAVE_METHOD_FLAGS_HI) != 0); - attr_defs[ATTR_CONTEXT_CODE] - .setHaveLongFlags((archive_options & AO_HAVE_CODE_FLAGS_HI) != 0); - - // Set up built-in attrs. - // (The simple ones are hard-coded. The metadata layouts are not.) - const char *md_layout = ( -// parameter annotations: -#define MDL0 "[NB[(1)]]" - MDL0 -// annotations: -#define MDL1 \ - "[NH[(1)]]" \ - "[RSHNH[RUH(1)]]" - MDL1 - // member_value: - "[TB" - "(66,67,73,83,90)[KIH]" - "(68)[KDH]" - "(70)[KFH]" - "(74)[KJH]" - "(99)[RSH]" - "(101)[RSHRUH]" - "(115)[RUH]" - "(91)[NH[(0)]]" - "(64)[" - // nested annotation: - "RSH" - "NH[RUH(0)]" - "]" - "()[]" - "]"); - - const char *md_layout_P = md_layout; - const char *md_layout_A = md_layout + strlen(MDL0); - const char *md_layout_V = md_layout + strlen(MDL0 MDL1); - assert(0 == strncmp(&md_layout_A[-3], ")]][", 4)); - assert(0 == strncmp(&md_layout_V[-3], ")]][", 4)); - - for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) - { - attr_definitions &ad = attr_defs[i]; - ad.defineLayout(X_ATTR_RuntimeVisibleAnnotations, "RuntimeVisibleAnnotations", - md_layout_A); - ad.defineLayout(X_ATTR_RuntimeInvisibleAnnotations, "RuntimeInvisibleAnnotations", - md_layout_A); - if (i != ATTR_CONTEXT_METHOD) - continue; - ad.defineLayout(METHOD_ATTR_RuntimeVisibleParameterAnnotations, - "RuntimeVisibleParameterAnnotations", md_layout_P); - ad.defineLayout(METHOD_ATTR_RuntimeInvisibleParameterAnnotations, - "RuntimeInvisibleParameterAnnotations", md_layout_P); - ad.defineLayout(METHOD_ATTR_AnnotationDefault, "AnnotationDefault", md_layout_V); - } - - attr_definition_headers.readData(attr_definition_count); - attr_definition_name.readData(attr_definition_count); - attr_definition_layout.readData(attr_definition_count); - -// Initialize correct predef bits, to distinguish predefs from new defs. -#define ORBIT(n, s) | ((uint64_t)1 << n) - attr_defs[ATTR_CONTEXT_CLASS].predef = (0 X_ATTR_DO(ORBIT) CLASS_ATTR_DO(ORBIT)); - attr_defs[ATTR_CONTEXT_FIELD].predef = (0 X_ATTR_DO(ORBIT) FIELD_ATTR_DO(ORBIT)); - attr_defs[ATTR_CONTEXT_METHOD].predef = (0 X_ATTR_DO(ORBIT) METHOD_ATTR_DO(ORBIT)); - attr_defs[ATTR_CONTEXT_CODE].predef = (0 O_ATTR_DO(ORBIT) CODE_ATTR_DO(ORBIT)); -#undef ORBIT - // Clear out the redef bits, folding them back into predef. - for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) - { - attr_defs[i].predef |= attr_defs[i].redef; - attr_defs[i].redef = 0; - } - - // Now read the transmitted locally defined attrs. - // This will set redef bits again. - for (i = 0; i < attr_definition_count; i++) - { - int header = attr_definition_headers.getByte(); - int attrc = ADH_BYTE_CONTEXT(header); - int idx = ADH_BYTE_INDEX(header); - entry *name = attr_definition_name.getRef(); - entry *layout = attr_definition_layout.getRef(); - attr_defs[attrc].defineLayout(idx, name, layout->value.b.strval()); - } -} - -#define NO_ENTRY_YET ((entry *)-1) - -static bool isDigitString(bytes &x, int beg, int end) -{ - if (beg == end) - return false; // nullptr string - byte *xptr = x.ptr; - for (int i = beg; i < end; i++) - { - char ch = xptr[i]; - if (!(ch >= '0' && ch <= '9')) - return false; - } - return true; -} - -enum -{ // constants for parsing class names - SLASH_MIN = '.', - SLASH_MAX = '/', - DOLLAR_MIN = 0, - DOLLAR_MAX = '-'}; - -static int lastIndexOf(int chmin, int chmax, bytes &x, int pos) -{ - byte *ptr = x.ptr; - for (byte *cp = ptr + pos; --cp >= ptr;) - { - assert(x.inBounds(cp)); - if (*cp >= chmin && *cp <= chmax) - return (int)(cp - ptr); - } - return -1; -} - -inner_class *constant_pool::getIC(entry *inner) -{ - if (inner == nullptr) - return nullptr; - assert(inner->tag == CONSTANT_Class); - if (inner->inord == NO_INORD) - return nullptr; - inner_class *ic = ic_index[inner->inord]; - assert(ic == nullptr || ic->inner == inner); - return ic; -} - -inner_class *constant_pool::getFirstChildIC(entry *outer) -{ - if (outer == nullptr) - return nullptr; - assert(outer->tag == CONSTANT_Class); - if (outer->inord == NO_INORD) - return nullptr; - inner_class *ic = ic_child_index[outer->inord]; - assert(ic == nullptr || ic->outer == outer); - return ic; -} - -inner_class *constant_pool::getNextChildIC(inner_class *child) -{ - inner_class *ic = child->next_sibling; - assert(ic == nullptr || ic->outer == child->outer); - return ic; -} - -void unpacker::read_ics() -{ - int i; - int index_size = cp.tag_count[CONSTANT_Class]; - inner_class **ic_index = U_NEW(inner_class *, index_size); - inner_class **ic_child_index = U_NEW(inner_class *, index_size); - cp.ic_index = ic_index; - cp.ic_child_index = ic_child_index; - ics = U_NEW(inner_class, ic_count); - ic_this_class.readData(ic_count); - ic_flags.readData(ic_count); - // Scan flags to get count of long-form bands. - int long_forms = 0; - for (i = 0; i < ic_count; i++) - { - int flags = ic_flags.getInt(); // may be long form! - if ((flags & ACC_IC_LONG_FORM) != 0) - { - long_forms += 1; - ics[i].name = NO_ENTRY_YET; - } - flags &= ~ACC_IC_LONG_FORM; - entry *inner = ic_this_class.getRef(); - uint32_t inord = inner->inord; - assert(inord < (uint32_t)cp.tag_count[CONSTANT_Class]); - if (ic_index[inord] != nullptr) - { - unpack_abort("identical inner class"); - break; - } - ic_index[inord] = &ics[i]; - ics[i].inner = inner; - ics[i].flags = flags; - assert(cp.getIC(inner) == &ics[i]); - } - // ic_this_class.done(); - // ic_flags.done(); - ic_outer_class.readData(long_forms); - ic_name.readData(long_forms); - for (i = 0; i < ic_count; i++) - { - if (ics[i].name == NO_ENTRY_YET) - { - // Long form. - ics[i].outer = ic_outer_class.getRefN(); - ics[i].name = ic_name.getRefN(); - } - else - { - // Fill in outer and name based on inner. - bytes &n = ics[i].inner->value.b; - bytes pkgOuter; - bytes number; - bytes name; - // Parse n into pkgOuter and name (and number). - int dollar1, dollar2; // pointers to $ in the pattern - // parse n = (/)*($)?($)? - int nlen = (int)n.len; - int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, nlen) + 1; - dollar2 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, nlen); - if (dollar2 < 0) - { - unpack_abort(); - } - assert(dollar2 >= pkglen); - if (isDigitString(n, dollar2 + 1, nlen)) - { - // n = (/)*$ - number = n.slice(dollar2 + 1, nlen); - name.set(nullptr, 0); - dollar1 = dollar2; - } - else if (pkglen < (dollar1 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, dollar2 - 1)) && - isDigitString(n, dollar1 + 1, dollar2)) - { - // n = (/)*$$ - number = n.slice(dollar1 + 1, dollar2); - name = n.slice(dollar2 + 1, nlen); - } - else - { - // n = (/)*$ - dollar1 = dollar2; - number.set(nullptr, 0); - name = n.slice(dollar2 + 1, nlen); - } - if (number.ptr == nullptr) - pkgOuter = n.slice(0, dollar1); - else - pkgOuter.set(nullptr, 0); - - if (pkgOuter.ptr != nullptr) - ics[i].outer = cp.ensureClass(pkgOuter); - - if (name.ptr != nullptr) - ics[i].name = cp.ensureUtf8(name); - } - - // update child/sibling list - if (ics[i].outer != nullptr) - { - uint32_t outord = ics[i].outer->inord; - if (outord != NO_INORD) - { - assert(outord < (uint32_t)cp.tag_count[CONSTANT_Class]); - ics[i].next_sibling = ic_child_index[outord]; - ic_child_index[outord] = &ics[i]; - } - } - } - // ic_outer_class.done(); - // ic_name.done(); -} - -void unpacker::read_classes() -{ - class_this.readData(class_count); - class_super.readData(class_count); - class_interface_count.readData(class_count); - class_interface.readData(class_interface_count.getIntTotal()); - -#if 0 - int i; - // Make a little mark on super-classes. - for (i = 0; i < class_count; i++) { - entry* e = class_super.getRefN(); - if (e != nullptr) e->bits |= entry::EB_SUPER; - } - class_super.rewind(); -#endif - - // Members. - class_field_count.readData(class_count); - class_method_count.readData(class_count); - - int field_count = class_field_count.getIntTotal(); - int method_count = class_method_count.getIntTotal(); - - field_descr.readData(field_count); - read_attrs(ATTR_CONTEXT_FIELD, field_count); - method_descr.readData(method_count); - read_attrs(ATTR_CONTEXT_METHOD, method_count); - read_attrs(ATTR_CONTEXT_CLASS, class_count); - read_code_headers(); -} - -int unpacker::attr_definitions::predefCount(uint32_t idx) -{ - return isPredefined(idx) ? flag_count[idx] : 0; -} - -void unpacker::read_attrs(int attrc, int obj_count) -{ - attr_definitions &ad = attr_defs[attrc]; - assert(ad.attrc == attrc); - - int i, idx, count; - - bool haveLongFlags = ad.haveLongFlags(); - - band &xxx_flags_hi = ad.xxx_flags_hi(); - if (haveLongFlags) - xxx_flags_hi.readData(obj_count); - - band &xxx_flags_lo = ad.xxx_flags_lo(); - xxx_flags_lo.readData(obj_count); - - // pre-scan flags, counting occurrences of each index bit - uint64_t indexMask = ad.flagIndexMask(); // which flag bits are index bits? - for (i = 0; i < obj_count; i++) - { - uint64_t indexBits = xxx_flags_hi.getLong(xxx_flags_lo, haveLongFlags); - if ((indexBits & ~indexMask) > (ushort) - 1) - { - unpack_abort("undefined attribute flag bit"); - return; - } - indexBits &= indexMask; // ignore classfile flag bits - for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) - { - ad.flag_count[idx] += (int)(indexBits & 1); - } - } - // we'll scan these again later for output: - xxx_flags_lo.rewind(); - xxx_flags_hi.rewind(); - - band &xxx_attr_count = ad.xxx_attr_count(); - // There is one count element for each 1<<16 bit set in flags: - xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW)); - - band &xxx_attr_indexes = ad.xxx_attr_indexes(); - int overflowIndexCount = xxx_attr_count.getIntTotal(); - xxx_attr_indexes.readData(overflowIndexCount); - // pre-scan attr indexes, counting occurrences of each value - for (i = 0; i < overflowIndexCount; i++) - { - idx = xxx_attr_indexes.getInt(); - if (!ad.isIndex(idx)) - { - unpack_abort("attribute index out of bounds"); - return; - } - ad.getCount(idx) += 1; - } - xxx_attr_indexes.rewind(); // we'll scan it again later for output - - // We will need a backward call count for each used backward callable. - int backwardCounts = 0; - for (idx = 0; idx < ad.layouts.length(); idx++) - { - layout_definition *lo = ad.getLayout(idx); - if (lo != nullptr && ad.getCount(idx) != 0) - { - // Build the bands lazily, only when they are used. - band **bands = ad.buildBands(lo); - if (lo->hasCallables()) - { - for (i = 0; bands[i] != nullptr; i++) - { - if (bands[i]->le_back) - { - assert(bands[i]->le_kind == EK_CBLE); - backwardCounts += 1; - } - } - } - } - } - ad.xxx_attr_calls().readData(backwardCounts); - - // Read built-in bands. - // Mostly, these are hand-coded equivalents to readBandData(). - switch (attrc) - { - case ATTR_CONTEXT_CLASS: - - count = ad.predefCount(CLASS_ATTR_SourceFile); - class_SourceFile_RUN.readData(count); - - count = ad.predefCount(CLASS_ATTR_EnclosingMethod); - class_EnclosingMethod_RC.readData(count); - class_EnclosingMethod_RDN.readData(count); - - count = ad.predefCount(X_ATTR_Signature); - class_Signature_RS.readData(count); - - ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); - ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); - - count = ad.predefCount(CLASS_ATTR_InnerClasses); - class_InnerClasses_N.readData(count); - - count = class_InnerClasses_N.getIntTotal(); - class_InnerClasses_RC.readData(count); - class_InnerClasses_F.readData(count); - - // Drop remaining columns wherever flags are zero: - count -= class_InnerClasses_F.getIntCount(0); - class_InnerClasses_outer_RCN.readData(count); - class_InnerClasses_name_RUN.readData(count); - - count = ad.predefCount(CLASS_ATTR_ClassFile_version); - class_ClassFile_version_minor_H.readData(count); - class_ClassFile_version_major_H.readData(count); - break; - - case ATTR_CONTEXT_FIELD: - - count = ad.predefCount(FIELD_ATTR_ConstantValue); - field_ConstantValue_KQ.readData(count); - - count = ad.predefCount(X_ATTR_Signature); - field_Signature_RS.readData(count); - - ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); - ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); - break; - - case ATTR_CONTEXT_METHOD: - - code_count = ad.predefCount(METHOD_ATTR_Code); - // Code attrs are handled very specially below... - - count = ad.predefCount(METHOD_ATTR_Exceptions); - method_Exceptions_N.readData(count); - count = method_Exceptions_N.getIntTotal(); - method_Exceptions_RC.readData(count); - - count = ad.predefCount(X_ATTR_Signature); - method_Signature_RS.readData(count); - - ad.readBandData(X_ATTR_RuntimeVisibleAnnotations); - ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations); - ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations); - ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations); - ad.readBandData(METHOD_ATTR_AnnotationDefault); - break; - - case ATTR_CONTEXT_CODE: - // (keep this code aligned with its brother in unpacker::write_attrs) - count = ad.predefCount(CODE_ATTR_StackMapTable); - // disable this feature in old archives! - if (count != 0 && majver < JAVA6_PACKAGE_MAJOR_VERSION) - { - unpack_abort("undefined StackMapTable attribute (old archive format)"); - return; - } - code_StackMapTable_N.readData(count); - count = code_StackMapTable_N.getIntTotal(); - code_StackMapTable_frame_T.readData(count); - // the rest of it depends in a complicated way on frame tags - { - int fat_frame_count = 0; - int offset_count = 0; - int type_count = 0; - for (int k = 0; k < count; k++) - { - int tag = code_StackMapTable_frame_T.getByte(); - if (tag <= 127) - { - // (64-127) [(2)] - if (tag >= 64) - type_count++; - } - else if (tag <= 251) - { - // (247) [(1)(2)] - // (248-251) [(1)] - if (tag >= 247) - offset_count++; - if (tag == 247) - type_count++; - } - else if (tag <= 254) - { - // (252) [(1)(2)] - // (253) [(1)(2)(2)] - // (254) [(1)(2)(2)(2)] - offset_count++; - type_count += (tag - 251); - } - else - { - // (255) [(1)NH[(2)]NH[(2)]] - fat_frame_count++; - } - } - - // done pre-scanning frame tags: - code_StackMapTable_frame_T.rewind(); - - // deal completely with fat frames: - offset_count += fat_frame_count; - code_StackMapTable_local_N.readData(fat_frame_count); - type_count += code_StackMapTable_local_N.getIntTotal(); - code_StackMapTable_stack_N.readData(fat_frame_count); - type_count += code_StackMapTable_stack_N.getIntTotal(); - // read the rest: - code_StackMapTable_offset.readData(offset_count); - code_StackMapTable_T.readData(type_count); - // (7) [RCH] - count = code_StackMapTable_T.getIntCount(7); - code_StackMapTable_RC.readData(count); - // (8) [PH] - count = code_StackMapTable_T.getIntCount(8); - code_StackMapTable_P.readData(count); - } - - count = ad.predefCount(CODE_ATTR_LineNumberTable); - code_LineNumberTable_N.readData(count); - count = code_LineNumberTable_N.getIntTotal(); - code_LineNumberTable_bci_P.readData(count); - code_LineNumberTable_line.readData(count); - - count = ad.predefCount(CODE_ATTR_LocalVariableTable); - code_LocalVariableTable_N.readData(count); - count = code_LocalVariableTable_N.getIntTotal(); - code_LocalVariableTable_bci_P.readData(count); - code_LocalVariableTable_span_O.readData(count); - code_LocalVariableTable_name_RU.readData(count); - code_LocalVariableTable_type_RS.readData(count); - code_LocalVariableTable_slot.readData(count); - - count = ad.predefCount(CODE_ATTR_LocalVariableTypeTable); - code_LocalVariableTypeTable_N.readData(count); - count = code_LocalVariableTypeTable_N.getIntTotal(); - code_LocalVariableTypeTable_bci_P.readData(count); - code_LocalVariableTypeTable_span_O.readData(count); - code_LocalVariableTypeTable_name_RU.readData(count); - code_LocalVariableTypeTable_type_RS.readData(count); - code_LocalVariableTypeTable_slot.readData(count); - break; - } - - // Read compressor-defined bands. - for (idx = 0; idx < ad.layouts.length(); idx++) - { - if (ad.getLayout(idx) == nullptr) - continue; // none at this fixed index <32 - if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) - continue; // already handled - if (ad.getCount(idx) == 0) - continue; // no attributes of this type (then why transmit layouts?) - ad.readBandData(idx); - } -} - -void unpacker::attr_definitions::readBandData(int idx) -{ - int j; - uint32_t count = getCount(idx); - if (count == 0) - return; - layout_definition *lo = getLayout(idx); - bool hasCallables = lo->hasCallables(); - band **bands = lo->bands(); - if (!hasCallables) - { - // Read through the rest of the bands in a regular way. - readBandData(bands, count); - } - else - { - // Deal with the callables. - // First set up the forward entry count for each callable. - // This is stored on band::length of the callable. - bands[0]->expectMoreLength(count); - for (j = 0; bands[j] != nullptr; j++) - { - band &j_cble = *bands[j]; - assert(j_cble.le_kind == EK_CBLE); - if (j_cble.le_back) - { - // Add in the predicted effects of backward calls, too. - int back_calls = xxx_attr_calls().getInt(); - j_cble.expectMoreLength(back_calls); - // In a moment, more forward calls may increment j_cble.length. - } - } - // Now consult whichever callables have non-zero entry counts. - readBandData(bands, (uint32_t) - 1); - } -} - -// Recursive helper to the previous function: -void unpacker::attr_definitions::readBandData(band **body, uint32_t count) -{ - int j, k; - for (j = 0; body[j] != nullptr; j++) - { - band &b = *body[j]; - if (b.defc != nullptr) - { - // It has data, so read it. - b.readData(count); - } - switch (b.le_kind) - { - case EK_REPL: - { - int reps = b.getIntTotal(); - readBandData(b.le_body, reps); - } - break; - case EK_UN: - { - int remaining = count; - for (k = 0; b.le_body[k] != nullptr; k++) - { - band &k_case = *b.le_body[k]; - int k_count = 0; - if (k_case.le_casetags == nullptr) - { - k_count = remaining; // last (empty) case - } - else - { - int *tags = k_case.le_casetags; - int ntags = *tags++; // 1st element is length (why not?) - while (ntags-- > 0) - { - int tag = *tags++; - k_count += b.getIntCount(tag); - } - } - readBandData(k_case.le_body, k_count); - remaining -= k_count; - } - assert(remaining == 0); - } - break; - case EK_CALL: - // Push the count forward, if it is not a backward call. - if (!b.le_back) - { - band &cble = *b.le_body[0]; - assert(cble.le_kind == EK_CBLE); - cble.expectMoreLength(count); - } - break; - case EK_CBLE: - assert((int)count == -1); // incoming count is meaningless - k = b.length; - assert(k >= 0); - // This is intended and required for non production mode. - assert((b.length = -1)); // make it unable to accept more calls now. - readBandData(b.le_body, k); - break; - } - } -} - -static inline band **findMatchingCase(int matchTag, band **cases) -{ - for (int k = 0; cases[k] != nullptr; k++) - { - band &k_case = *cases[k]; - if (k_case.le_casetags != nullptr) - { - // If it has tags, it must match a tag. - int *tags = k_case.le_casetags; - int ntags = *tags++; // 1st element is length - for (; ntags > 0; ntags--) - { - int tag = *tags++; - if (tag == matchTag) - break; - } - if (ntags == 0) - continue; // does not match - } - return k_case.le_body; - } - return nullptr; -} - -// write attribute band data: -void unpacker::putlayout(band **body) -{ - int i; - int prevBII = -1; - int prevBCI = -1; - if (body == NULL) - { - unpack_abort("putlayout: unexpected NULL for body"); - return; - } - for (i = 0; body[i] != nullptr; i++) - { - band &b = *body[i]; - byte le_kind = b.le_kind; - - // Handle scalar part, if any. - int x = 0; - entry *e = nullptr; - if (b.defc != nullptr) - { - // It has data, so unparse an element. - if (b.ixTag != CONSTANT_None) - { - assert(le_kind == EK_REF); - if (b.ixTag == CONSTANT_Literal) - e = b.getRefUsing(cp.getKQIndex()); - else - e = b.getRefN(); - switch (b.le_len) - { - case 0: - break; - case 1: - putu1ref(e); - break; - case 2: - putref(e); - break; - case 4: - putu2(0); - putref(e); - break; - default: - assert(false); - } - } - else - { - assert(le_kind == EK_INT || le_kind == EK_REPL || le_kind == EK_UN); - x = b.getInt(); - - assert(!b.le_bci || prevBCI == (int)to_bci(prevBII)); - switch (b.le_bci) - { - case EK_BCI: // PH: transmit R(bci), store bci - x = to_bci(prevBII = x); - prevBCI = x; - break; - case EK_BCID: // POH: transmit D(R(bci)), store bci - x = to_bci(prevBII += x); - prevBCI = x; - break; - case EK_BCO: // OH: transmit D(R(bci)), store D(bci) - x = to_bci(prevBII += x) - prevBCI; - prevBCI += x; - break; - } - assert(!b.le_bci || prevBCI == (int)to_bci(prevBII)); - - switch (b.le_len) - { - case 0: - break; - case 1: - putu1(x); - break; - case 2: - putu2(x); - break; - case 4: - putu4(x); - break; - default: - assert(false); - } - } - } - - // Handle subparts, if any. - switch (le_kind) - { - case EK_REPL: - // x is the repeat count - while (x-- > 0) - { - putlayout(b.le_body); - } - break; - case EK_UN: - // x is the tag - putlayout(findMatchingCase(x, b.le_body)); - break; - case EK_CALL: - { - band &cble = *b.le_body[0]; - assert(cble.le_kind == EK_CBLE); - // FIXME: hit this one - // assert(cble.le_len == b.le_len); - putlayout(cble.le_body); - } - break; - - case EK_CBLE: - case EK_CASE: - assert(false); // should not reach here - } - } -} - -void unpacker::read_files() -{ - file_name.readData(file_count); - if ((archive_options & AO_HAVE_FILE_SIZE_HI) != 0) - file_size_hi.readData(file_count); - file_size_lo.readData(file_count); - if ((archive_options & AO_HAVE_FILE_MODTIME) != 0) - file_modtime.readData(file_count); - int allFiles = file_count + class_count; - if ((archive_options & AO_HAVE_FILE_OPTIONS) != 0) - { - file_options.readData(file_count); - // FO_IS_CLASS_STUB might be set, causing overlap between classes and files - for (int i = 0; i < file_count; i++) - { - if ((file_options.getInt() & FO_IS_CLASS_STUB) != 0) - { - allFiles -= 1; // this one counts as both class and file - } - } - file_options.rewind(); - } - assert((default_file_options & FO_IS_CLASS_STUB) == 0); - files_remaining = allFiles; -} - -void unpacker::get_code_header(int &max_stack, int &max_na_locals, int &handler_count, - int &cflags) -{ - int sc = code_headers.getByte(); - if (sc == 0) - { - max_stack = max_na_locals = handler_count = cflags = -1; - return; - } - // Short code header is the usual case: - int nh; - int mod; - if (sc < 1 + 12 * 12) - { - sc -= 1; - nh = 0; - mod = 12; - } - else if (sc < 1 + 12 * 12 + 8 * 8) - { - sc -= 1 + 12 * 12; - nh = 1; - mod = 8; - } - else - { - assert(sc < 1 + 12 * 12 + 8 * 8 + 7 * 7); - sc -= 1 + 12 * 12 + 8 * 8; - nh = 2; - mod = 7; - } - max_stack = sc % mod; - max_na_locals = sc / mod; // caller must add static, siglen - handler_count = nh; - if ((archive_options & AO_HAVE_ALL_CODE_FLAGS) != 0) - cflags = -1; - else - cflags = 0; // this one has no attributes -} - -// Cf. PackageReader.readCodeHeaders -void unpacker::read_code_headers() -{ - code_headers.readData(code_count); - int totalHandlerCount = 0; - int totalFlagsCount = 0; - for (int i = 0; i < code_count; i++) - { - int max_stack, max_locals, handler_count, cflags; - get_code_header(max_stack, max_locals, handler_count, cflags); - if (max_stack < 0) - code_max_stack.expectMoreLength(1); - if (max_locals < 0) - code_max_na_locals.expectMoreLength(1); - if (handler_count < 0) - code_handler_count.expectMoreLength(1); - else - totalHandlerCount += handler_count; - if (cflags < 0) - totalFlagsCount += 1; - } - code_headers.rewind(); // replay later during writing - - code_max_stack.readData(); - code_max_na_locals.readData(); - code_handler_count.readData(); - totalHandlerCount += code_handler_count.getIntTotal(); - - // Read handler specifications. - // Cf. PackageReader.readCodeHandlers. - code_handler_start_P.readData(totalHandlerCount); - code_handler_end_PO.readData(totalHandlerCount); - code_handler_catch_PO.readData(totalHandlerCount); - code_handler_class_RCN.readData(totalHandlerCount); - - read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount); -} - -static inline bool is_in_range(uint32_t n, uint32_t min, uint32_t max) -{ - return n - min <= max - min; // unsigned arithmetic! -} -static inline bool is_field_op(int bc) -{ - return is_in_range(bc, bc_getstatic, bc_putfield); -} -static inline bool is_invoke_init_op(int bc) -{ - return is_in_range(bc, _invokeinit_op, _invokeinit_limit - 1); -} -static inline bool is_self_linker_op(int bc) -{ - return is_in_range(bc, _self_linker_op, _self_linker_limit - 1); -} -static bool is_branch_op(int bc) -{ - return is_in_range(bc, bc_ifeq, bc_jsr) || is_in_range(bc, bc_ifnull, bc_jsr_w); -} -static bool is_local_slot_op(int bc) -{ - return is_in_range(bc, bc_iload, bc_aload) || is_in_range(bc, bc_istore, bc_astore) || - bc == bc_iinc || bc == bc_ret; -} -band *unpacker::ref_band_for_op(int bc) -{ - switch (bc) - { - case bc_ildc: - case bc_ildc_w: - return &bc_intref; - case bc_fldc: - case bc_fldc_w: - return &bc_floatref; - case bc_lldc2_w: - return &bc_longref; - case bc_dldc2_w: - return &bc_doubleref; - case bc_aldc: - case bc_aldc_w: - return &bc_stringref; - case bc_cldc: - case bc_cldc_w: - return &bc_classref; - - case bc_getstatic: - case bc_putstatic: - case bc_getfield: - case bc_putfield: - return &bc_fieldref; - - case bc_invokevirtual: - case bc_invokespecial: - case bc_invokestatic: - return &bc_methodref; - case bc_invokeinterface: - return &bc_imethodref; - - case bc_new: - case bc_anewarray: - case bc_checkcast: - case bc_instanceof: - case bc_multianewarray: - return &bc_classref; - } - return nullptr; -} - -band *unpacker::ref_band_for_self_op(int bc, bool &isAloadVar, int &origBCVar) -{ - if (!is_self_linker_op(bc)) - return nullptr; - int idx = (bc - _self_linker_op); - bool isSuper = (idx >= _self_linker_super_flag); - if (isSuper) - idx -= _self_linker_super_flag; - bool isAload = (idx >= _self_linker_aload_flag); - if (isAload) - idx -= _self_linker_aload_flag; - int origBC = _first_linker_op + idx; - bool isField = is_field_op(origBC); - isAloadVar = isAload; - origBCVar = _first_linker_op + idx; - if (!isSuper) - return isField ? &bc_thisfield : &bc_thismethod; - else - return isField ? &bc_superfield : &bc_supermethod; -} - -// Cf. PackageReader.readByteCodes -inline // called exactly once => inline - void -unpacker::read_bcs() -{ - // read from bc_codes and bc_case_count - fillbytes all_switch_ops; - all_switch_ops.init(); - - // Read directly from rp/rplimit. - // Do this later: bc_codes.readData(...) - byte *rp0 = rp; - - band *bc_which; - byte *opptr = rp; - byte *oplimit = rplimit; - - bool isAload; // passed by ref and then ignored - int junkBC; // passed by ref and then ignored - for (int k = 0; k < code_count; k++) - { - // Scan one method: - for (;;) - { - if (opptr + 2 > oplimit) - { - rp = opptr; - ensure_input(2); - oplimit = rplimit; - rp = rp0; // back up - } - if (opptr == oplimit) - { - unpack_abort(); - } - int bc = *opptr++ & 0xFF; - bool isWide = false; - if (bc == bc_wide) - { - if (opptr == oplimit) - { - unpack_abort(); - } - bc = *opptr++ & 0xFF; - isWide = true; - } - // Adjust expectations of various band sizes. - switch (bc) - { - case bc_tableswitch: - case bc_lookupswitch: - all_switch_ops.addByte(bc); - break; - case bc_iinc: - bc_local.expectMoreLength(1); - bc_which = isWide ? &bc_short : &bc_byte; - bc_which->expectMoreLength(1); - break; - case bc_sipush: - bc_short.expectMoreLength(1); - break; - case bc_bipush: - bc_byte.expectMoreLength(1); - break; - case bc_newarray: - bc_byte.expectMoreLength(1); - break; - case bc_multianewarray: - assert(ref_band_for_op(bc) == &bc_classref); - bc_classref.expectMoreLength(1); - bc_byte.expectMoreLength(1); - break; - case bc_ref_escape: - bc_escrefsize.expectMoreLength(1); - bc_escref.expectMoreLength(1); - break; - case bc_byte_escape: - bc_escsize.expectMoreLength(1); - // bc_escbyte will have to be counted too - break; - default: - if (is_invoke_init_op(bc)) - { - bc_initref.expectMoreLength(1); - break; - } - bc_which = ref_band_for_self_op(bc, isAload, junkBC); - if (bc_which != nullptr) - { - bc_which->expectMoreLength(1); - break; - } - if (is_branch_op(bc)) - { - bc_label.expectMoreLength(1); - break; - } - bc_which = ref_band_for_op(bc); - if (bc_which != nullptr) - { - bc_which->expectMoreLength(1); - assert(bc != bc_multianewarray); // handled elsewhere - break; - } - if (is_local_slot_op(bc)) - { - bc_local.expectMoreLength(1); - break; - } - break; - case bc_end_marker: - // Increment k and test against code_count. - goto doneScanningMethod; - } - } - doneScanningMethod: - { - } - } - - // Go through the formality, so we can use it in a regular fashion later: - assert(rp == rp0); - bc_codes.readData((int)(opptr - rp)); - - int i = 0; - - // To size instruction bands correctly, we need info on switches: - bc_case_count.readData((int)all_switch_ops.size()); - for (i = 0; i < (int)all_switch_ops.size(); i++) - { - int caseCount = bc_case_count.getInt(); - int bc = all_switch_ops.getByte(i); - bc_label.expectMoreLength(1 + caseCount); // default label + cases - bc_case_value.expectMoreLength(bc == bc_tableswitch ? 1 : caseCount); - } - bc_case_count.rewind(); // uses again for output - - all_switch_ops.free(); - - for (i = e_bc_case_value; i <= e_bc_escsize; i++) - { - all_bands[i].readData(); - } - - // The bc_escbyte band is counted by the immediately previous band. - bc_escbyte.readData(bc_escsize.getIntTotal()); -} - -void unpacker::read_bands() -{ - read_file_header(); - - if (cp.nentries == 0) - { - // read_file_header failed to read a CP, because it copied a JAR. - return; - } - - // Do this after the file header has been read: - check_options(); - - read_cp(); - read_attr_defs(); - read_ics(); - read_classes(); - read_bcs(); - read_files(); -} - -/// CP routines - -entry *&constant_pool::hashTabRef(byte tag, bytes &b) -{ - uint32_t hash = tag + (int)b.len; - for (int i = 0; i < (int)b.len; i++) - { - hash = hash * 31 + (0xFF & b.ptr[i]); - } - entry **ht = hashTab; - int hlen = hashTabLength; - assert((hlen & (hlen - 1)) == 0); // must be power of 2 - uint32_t hash1 = hash & (hlen - 1); // == hash % hlen - uint32_t hash2 = 0; // lazily computed (requires mod op.) -#ifndef NDEBUG - int probes = 0; -#endif - while (ht[hash1] != nullptr) - { - entry &e = *ht[hash1]; - if (e.value.b.equals(b) && e.tag == tag) - break; - if (hash2 == 0) - // Note: hash2 must be relatively prime to hlen, hence the "|1". - hash2 = (((hash % 499) & (hlen - 1)) | 1); - hash1 += hash2; - if (hash1 >= (uint32_t)hlen) - hash1 -= hlen; - assert(hash1 < (uint32_t)hlen); - assert(++probes < hlen); - } - return ht[hash1]; -} - -static void insert_extra(entry *e, ptrlist &extras) -{ - // This ordering helps implement the Pack200 requirement - // of a predictable CP order in the class files produced. - e->inord = NO_INORD; // mark as an "extra" - extras.add(e); - // Note: We will sort the list (by string-name) later. -} - -entry *constant_pool::ensureUtf8(bytes &b) -{ - entry *&ix = hashTabRef(CONSTANT_Utf8, b); - if (ix != nullptr) - return ix; - // Make one. - if (nentries == maxentries) - { - unpack_abort("cp utf8 overflow"); - return &entries[tag_base[CONSTANT_Utf8]]; // return something - } - entry &e = entries[nentries++]; - e.tag = CONSTANT_Utf8; - u->saveTo(e.value.b, b); - assert(&e >= first_extra_entry); - insert_extra(&e, tag_extras[CONSTANT_Utf8]); - return ix = &e; -} - -entry *constant_pool::ensureClass(bytes &b) -{ - entry *&ix = hashTabRef(CONSTANT_Class, b); - if (ix != nullptr) - return ix; - // Make one. - if (nentries == maxentries) - { - unpack_abort("cp class overflow"); - return &entries[tag_base[CONSTANT_Class]]; // return something - } - entry &e = entries[nentries++]; - e.tag = CONSTANT_Class; - e.nrefs = 1; - e.refs = U_NEW(entry *, 1); - ix = &e; // hold my spot in the index - entry *utf = ensureUtf8(b); - e.refs[0] = utf; - e.value.b = utf->value.b; - assert(&e >= first_extra_entry); - insert_extra(&e, tag_extras[CONSTANT_Class]); - return &e; -} - -void constant_pool::expandSignatures() -{ - int i; - int nsigs = 0; - int nreused = 0; - int first_sig = tag_base[CONSTANT_Signature]; - int sig_limit = tag_count[CONSTANT_Signature] + first_sig; - fillbytes buf; - buf.init(1 << 10); - for (i = first_sig; i < sig_limit; i++) - { - entry &e = entries[i]; - assert(e.tag == CONSTANT_Signature); - int refnum = 0; - bytes form = e.refs[refnum++]->asUtf8(); - buf.empty(); - for (int j = 0; j < (int)form.len; j++) - { - int c = form.ptr[j]; - buf.addByte(c); - if (c == 'L') - { - entry *cls = e.refs[refnum++]; - buf.append(cls->className()->asUtf8()); - } - } - assert(refnum == e.nrefs); - bytes &sig = buf.b; - - // try to find a pre-existing Utf8: - entry *&e2 = hashTabRef(CONSTANT_Utf8, sig); - if (e2 != nullptr) - { - assert(e2->isUtf8(sig)); - e.value.b = e2->value.b; - e.refs[0] = e2; - e.nrefs = 1; - nreused++; - } - else - { - // there is no other replacement; reuse this CP entry as a Utf8 - u->saveTo(e.value.b, sig); - e.tag = CONSTANT_Utf8; - e.nrefs = 0; - e2 = &e; - } - nsigs++; - } - buf.free(); - - // go expunge all references to remaining signatures: - for (i = 0; i < (int)nentries; i++) - { - entry &e = entries[i]; - for (int j = 0; j < e.nrefs; j++) - { - entry *&e2 = e.refs[j]; - if (e2 != nullptr && e2->tag == CONSTANT_Signature) - e2 = e2->refs[0]; - } - } -} - -void constant_pool::initMemberIndexes() -{ - // This function does NOT refer to any class schema. - // It is totally internal to the cpool. - int i, j; - - // Get the pre-existing indexes: - int nclasses = tag_count[CONSTANT_Class]; - // entry *classes = tag_base[CONSTANT_Class] + entries; // UNUSED - int nfields = tag_count[CONSTANT_Fieldref]; - entry *fields = tag_base[CONSTANT_Fieldref] + entries; - int nmethods = tag_count[CONSTANT_Methodref]; - entry *methods = tag_base[CONSTANT_Methodref] + entries; - - int *field_counts = T_NEW(int, nclasses); - int *method_counts = T_NEW(int, nclasses); - cpindex *all_indexes = U_NEW(cpindex, nclasses * 2); - entry **field_ix = U_NEW(entry *, add_size(nfields, nclasses)); - entry **method_ix = U_NEW(entry *, add_size(nmethods, nclasses)); - - for (j = 0; j < nfields; j++) - { - entry &f = fields[j]; - i = f.memberClass()->inord; - assert(i < nclasses); - field_counts[i]++; - } - for (j = 0; j < nmethods; j++) - { - entry &m = methods[j]; - i = m.memberClass()->inord; - assert(i < nclasses); - method_counts[i]++; - } - - int fbase = 0, mbase = 0; - for (i = 0; i < nclasses; i++) - { - int fc = field_counts[i]; - int mc = method_counts[i]; - all_indexes[i * 2 + 0].init(fc, field_ix + fbase, CONSTANT_Fieldref + SUBINDEX_BIT); - all_indexes[i * 2 + 1].init(mc, method_ix + mbase, CONSTANT_Methodref + SUBINDEX_BIT); - // reuse field_counts and member_counts as fill pointers: - field_counts[i] = fbase; - method_counts[i] = mbase; - fbase += fc + 1; - mbase += mc + 1; - // (the +1 leaves a space between every subarray) - } - assert(fbase == nfields + nclasses); - assert(mbase == nmethods + nclasses); - - for (j = 0; j < nfields; j++) - { - entry &f = fields[j]; - i = f.memberClass()->inord; - field_ix[field_counts[i]++] = &f; - } - for (j = 0; j < nmethods; j++) - { - entry &m = methods[j]; - i = m.memberClass()->inord; - method_ix[method_counts[i]++] = &m; - } - - member_indexes = all_indexes; - - // Free intermediate buffers. - u->free_temps(); -} - -void entry::requestOutputIndex(constant_pool &cp, int req) -{ - assert(outputIndex <= NOT_REQUESTED); // must not have assigned indexes yet - if (tag == CONSTANT_Signature) - { - ref(0)->requestOutputIndex(cp, req); - return; - } - assert(req == REQUESTED || req == REQUESTED_LDC); - if (outputIndex != NOT_REQUESTED) - { - if (req == REQUESTED_LDC) - outputIndex = req; // this kind has precedence - return; - } - outputIndex = req; - // assert(!cp.outputEntries.contains(this)); - assert(tag != CONSTANT_Signature); - cp.outputEntries.add(this); - for (int j = 0; j < nrefs; j++) - { - ref(j)->requestOutputIndex(cp); - } -} - -void constant_pool::resetOutputIndexes() -{ - int i; - int noes = outputEntries.length(); - entry **oes = (entry **)outputEntries.base(); - for (i = 0; i < noes; i++) - { - entry &e = *oes[i]; - e.outputIndex = NOT_REQUESTED; - } - outputIndexLimit = 0; - outputEntries.empty(); -} - -static const byte TAG_ORDER[CONSTANT_Limit] = {0, 1, 0, 2, 3, 4, 5, 7, 6, 10, 11, 12, 9, 8}; - -extern "C" int outputEntry_cmp(const void *e1p, const void *e2p) -{ - // Sort entries according to the Pack200 rules for deterministic - // constant pool ordering. - // - // The four sort keys as follows, in order of decreasing importance: - // 1. ldc first, then non-ldc guys - // 2. normal cp_All entries by input order (i.e., address order) - // 3. after that, extra entries by lexical order (as in tag_extras[*]) - entry &e1 = *(entry *)*(void **)e1p; - entry &e2 = *(entry *)*(void **)e2p; - int oi1 = e1.outputIndex; - int oi2 = e2.outputIndex; - assert(oi1 == REQUESTED || oi1 == REQUESTED_LDC); - assert(oi2 == REQUESTED || oi2 == REQUESTED_LDC); - if (oi1 != oi2) - { - if (oi1 == REQUESTED_LDC) - return 0 - 1; - if (oi2 == REQUESTED_LDC) - return 1 - 0; - // Else fall through; neither is an ldc request. - } - if (e1.inord != NO_INORD || e2.inord != NO_INORD) - { - // One or both is normal. Use input order. - if (&e1 > &e2) - return 1 - 0; - if (&e1 < &e2) - return 0 - 1; - return 0; // equal pointers - } - // Both are extras. Sort by tag and then by value. - if (e1.tag != e2.tag) - { - return TAG_ORDER[e1.tag] - TAG_ORDER[e2.tag]; - } - // If the tags are the same, use string comparison. - return compare_Utf8_chars(e1.value.b, e2.value.b); -} - -void constant_pool::computeOutputIndexes() -{ - int i; - - int noes = outputEntries.length(); - entry **oes = (entry **)outputEntries.base(); - - // Sort the output constant pool into the order required by Pack200. - PTRLIST_QSORT(outputEntries, outputEntry_cmp); - - // Allocate a new index for each entry that needs one. - // We do this in two passes, one for LDC entries and one for the rest. - int nextIndex = 1; // always skip index #0 in output cpool - for (i = 0; i < noes; i++) - { - entry &e = *oes[i]; - assert(e.outputIndex == REQUESTED || e.outputIndex == REQUESTED_LDC); - e.outputIndex = nextIndex++; - if (e.isDoubleWord()) - nextIndex++; // do not use the next index - } - outputIndexLimit = nextIndex; -} - -// Unpacker Start -// Deallocate all internal storage and reset to a clean state. -// Do not disturb any input or output connections, including -// infileptr, inbytes, read_input_fn, jarout, or errstrm. -// Do not reset any unpack options. -void unpacker::reset() -{ - bytes_read_before_reset += bytes_read; - bytes_written_before_reset += bytes_written; - files_written_before_reset += files_written; - classes_written_before_reset += classes_written; - segments_read_before_reset += 1; - if (verbose >= 2) - { - fprintf(stderr, "After segment %d, %" PRIu64 " bytes read and %" PRIu64 " bytes written.\n", - segments_read_before_reset - 1, bytes_read_before_reset, - bytes_written_before_reset); - fprintf(stderr, - "After segment %d, %d files (of which %d are classes) written to output.\n", - segments_read_before_reset - 1, files_written_before_reset, - classes_written_before_reset); - if (archive_next_count != 0) - { - fprintf(stderr, "After segment %d, %d segment%s remaining (estimated).\n", - segments_read_before_reset - 1, archive_next_count, - archive_next_count == 1 ? "" : "s"); - } - } - - unpacker save_u = (*this); // save bytewise image - infileptr = nullptr; // make asserts happy - jarout = nullptr; // do not close the output jar - gzin = nullptr; // do not close the input gzip stream - this->free(); - this->init(read_input_fn); - - // restore selected interface state: - infileptr = save_u.infileptr; - inbytes = save_u.inbytes; - jarout = save_u.jarout; - gzin = save_u.gzin; - verbose = save_u.verbose; - deflate_hint_or_zero = save_u.deflate_hint_or_zero; - modification_time_or_zero = save_u.modification_time_or_zero; - bytes_read_before_reset = save_u.bytes_read_before_reset; - bytes_written_before_reset = save_u.bytes_written_before_reset; - files_written_before_reset = save_u.files_written_before_reset; - classes_written_before_reset = save_u.classes_written_before_reset; - segments_read_before_reset = save_u.segments_read_before_reset; - // Note: If we use strip_names, watch out: They get nuked here. -} - -void unpacker::init(read_input_fn_t input_fn) -{ - int i; - BYTES_OF(*this).clear(); - this->u = this; // self-reference for U_NEW macro - read_input_fn = input_fn; - all_bands = band::makeBands(this); - // Make a default jar buffer; caller may safely overwrite it. - jarout = U_NEW(jar, 1); - jarout->init(this); - for (i = 0; i < ATTR_CONTEXT_LIMIT; i++) - attr_defs[i].u = u; // set up outer ptr -} - -// Usage: unpack a byte buffer -// packptr is a reference to byte buffer containing a -// packed file and len is the length of the buffer. -// If nullptr, the callback is used to fill an internal buffer. -void unpacker::start(void *packptr, size_t len) -{ - if (packptr != nullptr && len != 0) - { - inbytes.set((byte *)packptr, len); - } - read_bands(); -} - -void unpacker::check_options() -{ - if (deflate_hint_or_zero != 0) - { - bool force_deflate_hint = (deflate_hint_or_zero > 0); - if (force_deflate_hint) - default_file_options |= FO_DEFLATE_HINT; - else - default_file_options &= ~FO_DEFLATE_HINT; - // Turn off per-file deflate hint by force. - suppress_file_options |= FO_DEFLATE_HINT; - } - if (modification_time_or_zero != 0) - { - default_file_modtime = modification_time_or_zero; - // Turn off per-file modtime by force. - archive_options &= ~AO_HAVE_FILE_MODTIME; - } -} - -// classfile writing - -void unpacker::reset_cur_classfile() -{ - // set defaults - cur_class_minver = default_class_minver; - cur_class_majver = default_class_majver; - - // reset constant pool state - cp.resetOutputIndexes(); - - // reset fixups - class_fixup_type.empty(); - class_fixup_offset.empty(); - class_fixup_ref.empty(); - requested_ics.empty(); -} - -cpindex *constant_pool::getKQIndex() -{ - char ch = '?'; - if (u->cur_descr != nullptr) - { - entry *type = u->cur_descr->descrType(); - ch = type->value.b.ptr[0]; - } - byte tag = CONSTANT_Integer; - switch (ch) - { - case 'L': - tag = CONSTANT_String; - break; - case 'I': - tag = CONSTANT_Integer; - break; - case 'J': - tag = CONSTANT_Long; - break; - case 'F': - tag = CONSTANT_Float; - break; - case 'D': - tag = CONSTANT_Double; - break; - case 'B': - case 'S': - case 'C': - case 'Z': - tag = CONSTANT_Integer; - break; - default: - unpack_abort("bad KQ reference"); - break; - } - return getIndex(tag); -} - -uint32_t unpacker::to_bci(uint32_t bii) -{ - uint32_t len = bcimap.length(); - uint32_t *map = (uint32_t *)bcimap.base(); - assert(len > 0); // must be initialized before using to_bci - if (bii < len) - return map[bii]; - // Else it's a fractional or out-of-range BCI. - uint32_t key = bii - len; - for (int i = len;; i--) - { - if (map[i - 1] - (i - 1) <= key) - break; - else - --bii; - } - return bii; -} - -void unpacker::put_stackmap_type() -{ - int tag = code_StackMapTable_T.getByte(); - putu1(tag); - switch (tag) - { - case 7: // (7) [RCH] - putref(code_StackMapTable_RC.getRef()); - break; - case 8: // (8) [PH] - putu2(to_bci(code_StackMapTable_P.getInt())); - break; - } -} - -// Functions for writing code. - -void unpacker::put_label(int curIP, int size) -{ - code_fixup_type.addByte(size); - code_fixup_offset.add((int)put_empty(size)); - code_fixup_source.add(curIP); -} - -inline // called exactly once => inline - void -unpacker::write_bc_ops() -{ - bcimap.empty(); - code_fixup_type.empty(); - code_fixup_offset.empty(); - code_fixup_source.empty(); - - band *bc_which; - - byte *opptr = bc_codes.curRP(); - // No need for oplimit, since the codes are pre-counted. - - size_t codeBase = wpoffset(); - - bool isAload; // copy-out result - int origBC; - - entry *thisClass = cur_class; - entry *superClass = cur_super; - entry *newClass = nullptr; // class of last _new opcode - - // overwrite any prior index on these bands; it changes w/ current class: - bc_thisfield.setIndex(cp.getFieldIndex(thisClass)); - bc_thismethod.setIndex(cp.getMethodIndex(thisClass)); - if (superClass != nullptr) - { - bc_superfield.setIndex(cp.getFieldIndex(superClass)); - bc_supermethod.setIndex(cp.getMethodIndex(superClass)); - } - - for (int curIP = 0;; curIP++) - { - int curPC = (int)(wpoffset() - codeBase); - bcimap.add(curPC); - ensure_put_space(10); // covers most instrs w/o further bounds check - int bc = *opptr++ & 0xFF; - - putu1_fast(bc); - // Note: See '--wp' below for pseudo-bytecodes like bc_end_marker. - - bool isWide = false; - if (bc == bc_wide) - { - bc = *opptr++ & 0xFF; - putu1_fast(bc); - isWide = true; - } - switch (bc) - { - case bc_end_marker: - --wp; // not really part of the code - assert(opptr <= bc_codes.maxRP()); - bc_codes.curRP() = opptr; // advance over this in bc_codes - goto doneScanningMethod; - case bc_tableswitch: // apc: (df, lo, hi, (hi-lo+1)*(label)) - case bc_lookupswitch: // apc: (df, nc, nc*(case, label)) - { - int caseCount = bc_case_count.getInt(); - while (((wpoffset() - codeBase) % 4) != 0) - putu1_fast(0); - ensure_put_space(30 + caseCount * 8); - put_label(curIP, 4); // int df = bc_label.getInt(); - if (bc == bc_tableswitch) - { - int lo = bc_case_value.getInt(); - int hi = lo + caseCount - 1; - putu4(lo); - putu4(hi); - for (int j = 0; j < caseCount; j++) - { - put_label(curIP, 4); // int lVal = bc_label.getInt(); - // int cVal = lo + j; - } - } - else - { - putu4(caseCount); - for (int j = 0; j < caseCount; j++) - { - int cVal = bc_case_value.getInt(); - putu4(cVal); - put_label(curIP, 4); // int lVal = bc_label.getInt(); - } - } - assert((int)to_bci(curIP) == curPC); - continue; - } - case bc_iinc: - { - int local = bc_local.getInt(); - int delta = (isWide ? bc_short : bc_byte).getInt(); - if (isWide) - { - putu2(local); - putu2(delta); - } - else - { - putu1_fast(local); - putu1_fast(delta); - } - continue; - } - case bc_sipush: - { - int val = bc_short.getInt(); - putu2(val); - continue; - } - case bc_bipush: - case bc_newarray: - { - int val = bc_byte.getByte(); - putu1_fast(val); - continue; - } - case bc_ref_escape: - { - // Note that insnMap has one entry for this. - --wp; // not really part of the code - int size = bc_escrefsize.getInt(); - entry *ref = bc_escref.getRefN(); - switch (size) - { - case 1: - putu1ref(ref); - break; - case 2: - putref(ref); - break; - default: - assert(false); - } - continue; - } - case bc_byte_escape: - { - // Note that insnMap has one entry for all these bytes. - --wp; // not really part of the code - int size = bc_escsize.getInt(); - ensure_put_space(size); - for (int j = 0; j < size; j++) - putu1_fast(bc_escbyte.getByte()); - continue; - } - default: - if (is_invoke_init_op(bc)) - { - origBC = bc_invokespecial; - entry *classRef; - switch (bc - _invokeinit_op) - { - case _invokeinit_self_option: - classRef = thisClass; - break; - case _invokeinit_super_option: - classRef = superClass; - break; - default: - assert(bc == _invokeinit_op + _invokeinit_new_option); - case _invokeinit_new_option: - classRef = newClass; - break; - } - wp[-1] = origBC; // overwrite with origBC - int coding = bc_initref.getInt(); - // Find the nth overloading of in classRef. - entry *ref = nullptr; - cpindex *ix = (classRef == nullptr) ? nullptr : cp.getMethodIndex(classRef); - for (int j = 0, which_init = 0;; j++) - { - ref = (ix == nullptr) ? nullptr : ix->get(j); - if (ref == nullptr) - break; // oops, bad input - assert(ref->tag == CONSTANT_Methodref); - if (ref->memberDescr()->descrName() == cp.sym[constant_pool::s_lt_init_gt]) - { - if (which_init++ == coding) - break; - } - } - putref(ref); - continue; - } - bc_which = ref_band_for_self_op(bc, isAload, origBC); - if (bc_which != nullptr) - { - if (!isAload) - { - wp[-1] = origBC; // overwrite with origBC - } - else - { - wp[-1] = bc_aload_0; // overwrite with _aload_0 - // Note: insnMap keeps the _aload_0 separate. - bcimap.add(++curPC); - ++curIP; - putu1_fast(origBC); - } - entry *ref = bc_which->getRef(); - putref(ref); - continue; - } - if (is_branch_op(bc)) - { - // int lVal = bc_label.getInt(); - if (bc < bc_goto_w) - { - put_label(curIP, 2); // putu2(lVal & 0xFFFF); - } - else - { - assert(bc <= bc_jsr_w); - put_label(curIP, 4); // putu4(lVal); - } - assert((int)to_bci(curIP) == curPC); - continue; - } - bc_which = ref_band_for_op(bc); - if (bc_which != nullptr) - { - entry *ref = bc_which->getRefCommon(bc_which->ix, bc_which->nullOK); - if (ref == nullptr && bc_which == &bc_classref) - { - // Shorthand for class self-references. - ref = thisClass; - } - origBC = bc; - switch (bc) - { - case bc_ildc: - case bc_cldc: - case bc_fldc: - case bc_aldc: - origBC = bc_ldc; - break; - case bc_ildc_w: - case bc_cldc_w: - case bc_fldc_w: - case bc_aldc_w: - origBC = bc_ldc_w; - break; - case bc_lldc2_w: - case bc_dldc2_w: - origBC = bc_ldc2_w; - break; - case bc_new: - newClass = ref; - break; - } - wp[-1] = origBC; // overwrite with origBC - if (origBC == bc_ldc) - { - putu1ref(ref); - } - else - { - putref(ref); - } - if (origBC == bc_multianewarray) - { - // Copy the trailing byte also. - int val = bc_byte.getByte(); - putu1_fast(val); - } - else if (origBC == bc_invokeinterface) - { - int argSize = ref->memberDescr()->descrType()->typeSize(); - putu1_fast(1 + argSize); - putu1_fast(0); - } - continue; - } - if (is_local_slot_op(bc)) - { - int local = bc_local.getInt(); - if (isWide) - { - putu2(local); - if (bc == bc_iinc) - { - int iVal = bc_short.getInt(); - putu2(iVal); - } - } - else - { - putu1_fast(local); - if (bc == bc_iinc) - { - int iVal = bc_byte.getByte(); - putu1_fast(iVal); - } - } - continue; - } - // Random bytecode. Just copy it. - assert(bc < bc_bytecode_limit); - } - } -doneScanningMethod: -{ -} - // bcimap.add(curPC); // PC limit is already also in map, from bc_end_marker - - // Armed with a bcimap, we can now fix up all the labels. - for (int i = 0; i < (int)code_fixup_type.size(); i++) - { - int type = code_fixup_type.getByte(i); - byte *bp = wp_at(code_fixup_offset.get(i)); - int curIP = code_fixup_source.get(i); - int destIP = curIP + bc_label.getInt(); - int span = to_bci(destIP) - to_bci(curIP); - switch (type) - { - case 2: - putu2_at(bp, (ushort)span); - break; - case 4: - putu4_at(bp, span); - break; - default: - assert(false); - } - } -} - -inline // called exactly once => inline - void -unpacker::write_code() -{ - int j; - - int max_stack, max_locals, handler_count, cflags; - get_code_header(max_stack, max_locals, handler_count, cflags); - - if (max_stack < 0) - max_stack = code_max_stack.getInt(); - if (max_locals < 0) - max_locals = code_max_na_locals.getInt(); - if (handler_count < 0) - handler_count = code_handler_count.getInt(); - - int siglen = cur_descr->descrType()->typeSize(); - if ((cur_descr_flags & ACC_STATIC) == 0) - siglen++; - max_locals += siglen; - - putu2(max_stack); - putu2(max_locals); - size_t bcbase = put_empty(4); - - // Write the bytecodes themselves. - write_bc_ops(); - - byte *bcbasewp = wp_at(bcbase); - putu4_at(bcbasewp, (int)(wp - (bcbasewp + 4))); // size of code attr - - putu2(handler_count); - for (j = 0; j < handler_count; j++) - { - int bii = code_handler_start_P.getInt(); - putu2(to_bci(bii)); - bii += code_handler_end_PO.getInt(); - putu2(to_bci(bii)); - bii += code_handler_catch_PO.getInt(); - putu2(to_bci(bii)); - putref(code_handler_class_RCN.getRefN()); - } - - uint64_t indexBits = cflags; - if (cflags < 0) - { - bool haveLongFlags = attr_defs[ATTR_CONTEXT_CODE].haveLongFlags(); - indexBits = code_flags_hi.getLong(code_flags_lo, haveLongFlags); - } - write_attrs(ATTR_CONTEXT_CODE, indexBits); -} - -int unpacker::write_attrs(int attrc, uint64_t indexBits) -{ - if (indexBits == 0) - { - // Quick short-circuit. - putu2(0); - return 0; - } - - attr_definitions &ad = attr_defs[attrc]; - - int i, j, j2, idx, count; - - int oiCount = 0; - if (ad.isPredefined(X_ATTR_OVERFLOW) && (indexBits & ((uint64_t)1 << X_ATTR_OVERFLOW)) != 0) - { - indexBits -= ((uint64_t)1 << X_ATTR_OVERFLOW); - oiCount = ad.xxx_attr_count().getInt(); - } - - int bitIndexes[X_ATTR_LIMIT_FLAGS_HI]; - int biCount = 0; - - // Fill bitIndexes with index bits, in order. - for (idx = 0; indexBits != 0; idx++, indexBits >>= 1) - { - if ((indexBits & 1) != 0) - bitIndexes[biCount++] = idx; - } - assert(biCount <= (int)lengthof(bitIndexes)); - - // Write a provisional attribute count, perhaps to be corrected later. - int naOffset = (int)wpoffset(); - int na0 = biCount + oiCount; - putu2(na0); - - int na = 0; - for (i = 0; i < na0; i++) - { - if (i < biCount) - idx = bitIndexes[i]; - else - idx = ad.xxx_attr_indexes().getInt(); - assert(ad.isIndex(idx)); - entry *aname = nullptr; - entry *ref; // scratch - size_t abase = put_empty(2 + 4); - if (idx < (int)ad.flag_limit && ad.isPredefined(idx)) - { - // Switch on the attrc and idx simultaneously. - switch (ADH_BYTE(attrc, idx)) - { - - case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_OVERFLOW) : - case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_OVERFLOW) : - case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_OVERFLOW) : - case ADH_BYTE(ATTR_CONTEXT_CODE, X_ATTR_OVERFLOW) : - // no attribute at all, so back up on this one - wp = wp_at(abase); - continue; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_ClassFile_version) : - cur_class_minver = class_ClassFile_version_minor_H.getInt(); - cur_class_majver = class_ClassFile_version_major_H.getInt(); - // back up; not a real attribute - wp = wp_at(abase); - continue; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_InnerClasses) : - // note the existence of this attr, but save for later - if (cur_class_has_local_ics) - unpack_abort("too many InnerClasses attrs"); - cur_class_has_local_ics = true; - wp = wp_at(abase); - continue; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_SourceFile) : - aname = cp.sym[constant_pool::s_SourceFile]; - ref = class_SourceFile_RUN.getRefN(); - if (ref == nullptr) - { - bytes &n = cur_class->ref(0)->value.b; - // parse n = (/)*?($)* - int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, (int)n.len) + 1; - bytes prefix = n.slice(pkglen, n.len); - for (;;) - { - // Work backwards, finding all '$', '#', etc. - int dollar = - lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, prefix, (int)prefix.len); - if (dollar < 0) - break; - prefix = prefix.slice(0, dollar); - } - const char *suffix = ".java"; - int len = (int)(prefix.len + strlen(suffix)); - bytes name; - name.set(T_NEW(byte, add_size(len, 1)), len); - name.strcat(prefix).strcat(suffix); - ref = cp.ensureUtf8(name); - } - putref(ref); - break; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, CLASS_ATTR_EnclosingMethod) : - aname = cp.sym[constant_pool::s_EnclosingMethod]; - putref(class_EnclosingMethod_RC.getRefN()); - putref(class_EnclosingMethod_RDN.getRefN()); - break; - - case ADH_BYTE(ATTR_CONTEXT_FIELD, FIELD_ATTR_ConstantValue) : - aname = cp.sym[constant_pool::s_ConstantValue]; - putref(field_ConstantValue_KQ.getRefUsing(cp.getKQIndex())); - break; - - case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Code) : - aname = cp.sym[constant_pool::s_Code]; - write_code(); - break; - - case ADH_BYTE(ATTR_CONTEXT_METHOD, METHOD_ATTR_Exceptions) : - aname = cp.sym[constant_pool::s_Exceptions]; - putu2(count = method_Exceptions_N.getInt()); - for (j = 0; j < count; j++) - { - putref(method_Exceptions_RC.getRefN()); - } - break; - - case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_StackMapTable) : - aname = cp.sym[constant_pool::s_StackMapTable]; - // (keep this code aligned with its brother in unpacker::read_attrs) - putu2(count = code_StackMapTable_N.getInt()); - for (j = 0; j < count; j++) - { - int tag = code_StackMapTable_frame_T.getByte(); - putu1(tag); - if (tag <= 127) - { - // (64-127) [(2)] - if (tag >= 64) - put_stackmap_type(); - } - else if (tag <= 251) - { - // (247) [(1)(2)] - // (248-251) [(1)] - if (tag >= 247) - putu2(code_StackMapTable_offset.getInt()); - if (tag == 247) - put_stackmap_type(); - } - else if (tag <= 254) - { - // (252) [(1)(2)] - // (253) [(1)(2)(2)] - // (254) [(1)(2)(2)(2)] - putu2(code_StackMapTable_offset.getInt()); - for (int k = (tag - 251); k > 0; k--) - { - put_stackmap_type(); - } - } - else - { - // (255) [(1)NH[(2)]NH[(2)]] - putu2(code_StackMapTable_offset.getInt()); - putu2(j2 = code_StackMapTable_local_N.getInt()); - while (j2-- > 0) - put_stackmap_type(); - putu2(j2 = code_StackMapTable_stack_N.getInt()); - while (j2-- > 0) - put_stackmap_type(); - } - } - break; - - case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LineNumberTable) : - aname = cp.sym[constant_pool::s_LineNumberTable]; - putu2(count = code_LineNumberTable_N.getInt()); - for (j = 0; j < count; j++) - { - putu2(to_bci(code_LineNumberTable_bci_P.getInt())); - putu2(code_LineNumberTable_line.getInt()); - } - break; - - case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTable) : - aname = cp.sym[constant_pool::s_LocalVariableTable]; - putu2(count = code_LocalVariableTable_N.getInt()); - for (j = 0; j < count; j++) - { - int bii = code_LocalVariableTable_bci_P.getInt(); - int bci = to_bci(bii); - putu2(bci); - bii += code_LocalVariableTable_span_O.getInt(); - putu2(to_bci(bii) - bci); - putref(code_LocalVariableTable_name_RU.getRefN()); - putref(code_LocalVariableTable_type_RS.getRefN()); - putu2(code_LocalVariableTable_slot.getInt()); - } - break; - - case ADH_BYTE(ATTR_CONTEXT_CODE, CODE_ATTR_LocalVariableTypeTable) : - aname = cp.sym[constant_pool::s_LocalVariableTypeTable]; - putu2(count = code_LocalVariableTypeTable_N.getInt()); - for (j = 0; j < count; j++) - { - int bii = code_LocalVariableTypeTable_bci_P.getInt(); - int bci = to_bci(bii); - putu2(bci); - bii += code_LocalVariableTypeTable_span_O.getInt(); - putu2(to_bci(bii) - bci); - putref(code_LocalVariableTypeTable_name_RU.getRefN()); - putref(code_LocalVariableTypeTable_type_RS.getRefN()); - putu2(code_LocalVariableTypeTable_slot.getInt()); - } - break; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Signature) : - aname = cp.sym[constant_pool::s_Signature]; - putref(class_Signature_RS.getRefN()); - break; - - case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Signature) : - aname = cp.sym[constant_pool::s_Signature]; - putref(field_Signature_RS.getRefN()); - break; - - case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Signature) : - aname = cp.sym[constant_pool::s_Signature]; - putref(method_Signature_RS.getRefN()); - break; - - case ADH_BYTE(ATTR_CONTEXT_CLASS, X_ATTR_Deprecated) : - case ADH_BYTE(ATTR_CONTEXT_FIELD, X_ATTR_Deprecated) : - case ADH_BYTE(ATTR_CONTEXT_METHOD, X_ATTR_Deprecated) : - aname = cp.sym[constant_pool::s_Deprecated]; - // no data - break; - } - } - - if (aname == nullptr) - { - // Unparse a compressor-defined attribute. - layout_definition *lo = ad.getLayout(idx); - if (lo == nullptr) - { - unpack_abort("bad layout index"); - break; - } - assert((int)lo->idx == idx); - aname = lo->nameEntry; - if (aname == nullptr) - { - bytes nameb; - nameb.set(lo->name); - aname = cp.ensureUtf8(nameb); - // Cache the name entry for next time. - lo->nameEntry = aname; - } - // Execute all the layout elements. - band **bands = lo->bands(); - if (lo->hasCallables()) - { - band &cble = *bands[0]; - assert(cble.le_kind == EK_CBLE); - bands = cble.le_body; - } - putlayout(bands); - } - - if (aname == nullptr) - unpack_abort("bad attribute index"); - - byte *wp1 = wp; - wp = wp_at(abase); - - // DTRT if this attr is on the strip-list. - // (Note that we emptied the data out of the band first.) - if (ad.strip_names.contains(aname)) - { - continue; - } - - // patch the name and length - putref(aname); - putu4((int)(wp1 - (wp + 4))); // put the attr size - wp = wp1; - na++; // count the attrs actually written - } - - if (na != na0) - // Refresh changed count. - putu2_at(wp_at(naOffset), na); - return na; -} - -void unpacker::write_members(int num, int attrc) -{ - attr_definitions &ad = attr_defs[attrc]; - band &member_flags_hi = ad.xxx_flags_hi(); - band &member_flags_lo = ad.xxx_flags_lo(); - band &member_descr = (&member_flags_hi)[e_field_descr - e_field_flags_hi]; - bool haveLongFlags = ad.haveLongFlags(); - - putu2(num); - uint64_t indexMask = attr_defs[attrc].flagIndexMask(); - for (int i = 0; i < num; i++) - { - uint64_t mflags = member_flags_hi.getLong(member_flags_lo, haveLongFlags); - entry *mdescr = member_descr.getRef(); - cur_descr = mdescr; - putu2(cur_descr_flags = (ushort)(mflags & ~indexMask)); - putref(mdescr->descrName()); - putref(mdescr->descrType()); - write_attrs(attrc, (mflags & indexMask)); - } - cur_descr = nullptr; -} - -extern "C" int raw_address_cmp(const void *p1p, const void *p2p) -{ - void *p1 = *(void **)p1p; - void *p2 = *(void **)p2p; - return (p1 > p2) ? 1 : (p1 < p2) ? -1 : 0; -} - -void unpacker::write_classfile_tail() -{ - cur_classfile_tail.empty(); - set_output(&cur_classfile_tail); - - int i, num; - - attr_definitions &ad = attr_defs[ATTR_CONTEXT_CLASS]; - - bool haveLongFlags = ad.haveLongFlags(); - uint64_t kflags = class_flags_hi.getLong(class_flags_lo, haveLongFlags); - uint64_t indexMask = ad.flagIndexMask(); - - cur_class = class_this.getRef(); - cur_super = class_super.getRef(); - - if (cur_super == cur_class) - cur_super = nullptr; - // special representation for java/lang/Object - - putu2((ushort)(kflags & ~indexMask)); - putref(cur_class); - putref(cur_super); - - putu2(num = class_interface_count.getInt()); - for (i = 0; i < num; i++) - { - putref(class_interface.getRef()); - } - - write_members(class_field_count.getInt(), ATTR_CONTEXT_FIELD); - write_members(class_method_count.getInt(), ATTR_CONTEXT_METHOD); - - cur_class_has_local_ics = false; // may be set true by write_attrs - - int naOffset = (int)wpoffset(); - int na = write_attrs(ATTR_CONTEXT_CLASS, (kflags & indexMask)); - -// at the very last, choose which inner classes (if any) pertain to k: -#ifdef ASSERT - for (i = 0; i < ic_count; i++) - { - assert(!ics[i].requested); - } -#endif - // First, consult the global table and the local constant pool, - // and decide on the globally implied inner classes. - // (Note that we read the cpool's outputIndex fields, but we - // do not yet write them, since the local IC attribute might - // reverse a global decision to declare an IC.) - assert(requested_ics.length() == 0); // must start out empty - // Always include all members of the current class. - for (inner_class *child = cp.getFirstChildIC(cur_class); child != nullptr; - child = cp.getNextChildIC(child)) - { - child->requested = true; - requested_ics.add(child); - } - // And, for each inner class mentioned in the constant pool, - // include it and all its outers. - int noes = cp.outputEntries.length(); - entry **oes = (entry **)cp.outputEntries.base(); - for (i = 0; i < noes; i++) - { - entry &e = *oes[i]; - if (e.tag != CONSTANT_Class) - continue; // wrong sort - for (inner_class *ic = cp.getIC(&e); ic != nullptr; ic = cp.getIC(ic->outer)) - { - if (ic->requested) - break; // already processed - ic->requested = true; - requested_ics.add(ic); - } - } - int local_ics = requested_ics.length(); - // Second, consult a local attribute (if any) and adjust the global set. - inner_class *extra_ics = nullptr; - int num_extra_ics = 0; - if (cur_class_has_local_ics) - { - // adjust the set of ICs by symmetric set difference w/ the locals - num_extra_ics = class_InnerClasses_N.getInt(); - if (num_extra_ics == 0) - { - // Explicit zero count has an irregular meaning: It deletes the attr. - local_ics = 0; // (short-circuit all tests of requested bits) - } - else - { - extra_ics = T_NEW(inner_class, num_extra_ics); - // Note: extra_ics will be freed up by next call to get_next_file(). - } - } - for (i = 0; i < num_extra_ics; i++) - { - inner_class &extra_ic = extra_ics[i]; - extra_ic.inner = class_InnerClasses_RC.getRef(); - // Find the corresponding equivalent global IC: - inner_class *global_ic = cp.getIC(extra_ic.inner); - int flags = class_InnerClasses_F.getInt(); - if (flags == 0) - { - // The extra IC is simply a copy of a global IC. - if (global_ic == nullptr) - { - unpack_abort("bad reference to inner class"); - break; - } - extra_ic = (*global_ic); // fill in rest of fields - } - else - { - flags &= ~ACC_IC_LONG_FORM; // clear high bit if set to get clean zero - extra_ic.flags = flags; - extra_ic.outer = class_InnerClasses_outer_RCN.getRefN(); - extra_ic.name = class_InnerClasses_name_RUN.getRefN(); - // Detect if this is an exact copy of the global tuple. - if (global_ic != nullptr) - { - if (global_ic->flags != extra_ic.flags || global_ic->outer != extra_ic.outer || - global_ic->name != extra_ic.name) - { - global_ic = nullptr; // not really the same, so break the link - } - } - } - if (global_ic != nullptr && global_ic->requested) - { - // This local repetition reverses the globally implied request. - global_ic->requested = false; - extra_ic.requested = false; - local_ics -= 1; - } - else - { - // The global either does not exist, or is not yet requested. - extra_ic.requested = true; - local_ics += 1; - } - } - // Finally, if there are any that survived, put them into an attribute. - // (Note that a zero-count attribute is always deleted.) - // The putref calls below will tell the constant pool to add any - // necessary local CP references to support the InnerClasses attribute. - // This step must be the last round of additions to the local CP. - if (local_ics > 0) - { - // append the new attribute: - putref(cp.sym[constant_pool::s_InnerClasses]); - putu4(2 + 2 * 4 * local_ics); - putu2(local_ics); - PTRLIST_QSORT(requested_ics, raw_address_cmp); - int num_global_ics = requested_ics.length(); - for (i = -num_global_ics; i < num_extra_ics; i++) - { - inner_class *ic; - if (i < 0) - ic = (inner_class *)requested_ics.get(num_global_ics + i); - else - ic = &extra_ics[i]; - if (ic->requested) - { - putref(ic->inner); - putref(ic->outer); - putref(ic->name); - putu2(ic->flags); - } - } - putu2_at(wp_at(naOffset), ++na); // increment class attr count - } - - // Tidy up global 'requested' bits: - for (i = requested_ics.length(); --i >= 0;) - { - inner_class *ic = (inner_class *)requested_ics.get(i); - ic->requested = false; - } - requested_ics.empty(); - - close_output(); - - // rewrite CP references in the tail - cp.computeOutputIndexes(); - int nextref = 0; - for (i = 0; i < (int)class_fixup_type.size(); i++) - { - int type = class_fixup_type.getByte(i); - byte *fixp = wp_at(class_fixup_offset.get(i)); - entry *e = (entry *)class_fixup_ref.get(nextref++); - int idx = e->getOutputIndex(); - switch (type) - { - case 1: - putu1_at(fixp, idx); - break; - case 2: - putu2_at(fixp, idx); - break; - default: - assert(false); // should not reach here - } - } -} - -void unpacker::write_classfile_head() -{ - cur_classfile_head.empty(); - set_output(&cur_classfile_head); - - putu4(JAVA_MAGIC); - putu2(cur_class_minver); - putu2(cur_class_majver); - putu2(cp.outputIndexLimit); - -#ifndef NDEBUG - int checkIndex = 1; -#endif - int noes = cp.outputEntries.length(); - entry **oes = (entry **)cp.outputEntries.base(); - for (int i = 0; i < noes; i++) - { - entry &e = *oes[i]; - assert(e.getOutputIndex() == checkIndex++); - byte tag = e.tag; - assert(tag != CONSTANT_Signature); - putu1(tag); - switch (tag) - { - case CONSTANT_Utf8: - putu2((int)e.value.b.len); - put_bytes(e.value.b); - break; - case CONSTANT_Integer: - case CONSTANT_Float: - putu4(e.value.i); - break; - case CONSTANT_Long: - case CONSTANT_Double: - putu8(e.value.l); - assert(checkIndex++); - break; - case CONSTANT_Class: - case CONSTANT_String: - // just write the ref - putu2(e.refs[0]->getOutputIndex()); - break; - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - case CONSTANT_NameandType: - putu2(e.refs[0]->getOutputIndex()); - putu2(e.refs[1]->getOutputIndex()); - break; - default: - unpack_abort(ERROR_INTERNAL); - } - } - close_output(); -} - -unpacker::file *unpacker::get_next_file() -{ - free_temps(); - if (files_remaining == 0) - { - // Leave a clue that we're exhausted. - cur_file.name = nullptr; - cur_file.size = 0; - if (archive_size != 0) - { - uint64_t predicted_size = unsized_bytes_read + archive_size; - if (predicted_size != bytes_read) - unpack_abort("archive header had incorrect size"); - } - return nullptr; - } - files_remaining -= 1; - assert(files_written < file_count || classes_written < class_count); - cur_file.name = ""; - cur_file.size = 0; - cur_file.modtime = default_file_modtime; - cur_file.options = default_file_options; - cur_file.data[0].set(nullptr, 0); - cur_file.data[1].set(nullptr, 0); - if (files_written < file_count) - { - entry *e = file_name.getRef(); - cur_file.name = e->utf8String(); - bool haveLongSize = ((archive_options & AO_HAVE_FILE_SIZE_HI) != 0); - cur_file.size = file_size_hi.getLong(file_size_lo, haveLongSize); - if ((archive_options & AO_HAVE_FILE_MODTIME) != 0) - cur_file.modtime += file_modtime.getInt(); // relative to archive modtime - if ((archive_options & AO_HAVE_FILE_OPTIONS) != 0) - cur_file.options |= file_options.getInt() & ~suppress_file_options; - } - else if (classes_written < class_count) - { - // there is a class for a missing file record - cur_file.options |= FO_IS_CLASS_STUB; - } - if ((cur_file.options & FO_IS_CLASS_STUB) != 0) - { - assert(classes_written < class_count); - classes_written += 1; - if (cur_file.size != 0) - { - unpack_abort("class file size transmitted"); - } - reset_cur_classfile(); - - // write the meat of the classfile: - write_classfile_tail(); - cur_file.data[1] = cur_classfile_tail.b; - - // write the CP of the classfile, second: - write_classfile_head(); - cur_file.data[0] = cur_classfile_head.b; - - cur_file.size += cur_file.data[0].len; - cur_file.size += cur_file.data[1].len; - if (cur_file.name[0] == '\0') - { - bytes &prefix = cur_class->ref(0)->value.b; - const char *suffix = ".class"; - int len = (int)(prefix.len + strlen(suffix)); - bytes name; - name.set(T_NEW(byte, add_size(len, 1)), len); - cur_file.name = name.strcat(prefix).strcat(suffix).strval(); - } - } - else - { - // If there is buffered file data, produce a pointer to it. - if (cur_file.size != (size_t)cur_file.size) - { - // Silly size specified. - unpack_abort("resource file too large"); - } - size_t rpleft = input_remaining(); - if (rpleft > 0) - { - if (rpleft > cur_file.size) - rpleft = (size_t)cur_file.size; - cur_file.data[0].set(rp, rpleft); - rp += rpleft; - } - if (rpleft < cur_file.size) - { - // Caller must read the rest. - size_t fleft = (size_t)cur_file.size - rpleft; - bytes_read += fleft; // Credit it to the overall archive size. - } - } - bytes_written += cur_file.size; - files_written += 1; - return &cur_file; -} - -// Write a file to jarout. -void unpacker::write_file_to_jar(unpacker::file *f) -{ - size_t htsize = f->data[0].len + f->data[1].len; - uint64_t fsize = f->size; - if (htsize == fsize) - { - jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime, f->data[0], f->data[1]); - } - else - { - assert(input_remaining() == 0); - bytes part1, part2; - part1.len = f->data[0].len; - part1.set(T_NEW(byte, part1.len), part1.len); - part1.copyFrom(f->data[0]); - assert(f->data[1].len == 0); - part2.set(nullptr, 0); - size_t fleft = (size_t)fsize - part1.len; - assert(bytes_read > fleft); // part2 already credited by get_next_file - bytes_read -= fleft; - if (fleft > 0) - { - // Must read some more. - if (live_input) - { - // Stop using the input buffer. Make a new one: - if (free_input) - input.free(); - input.init(fleft > (1 << 12) ? fleft : (1 << 12)); - free_input = true; - live_input = false; - } - else - { - // Make it large enough. - assert(free_input); // must be reallocable - input.ensureSize(fleft); - } - rplimit = rp = input.base(); - input.setLimit(rp + fleft); - if (!ensure_input(fleft)) - unpack_abort("EOF reading resource file"); - part2.ptr = input_scan(); - part2.len = input_remaining(); - rplimit = rp = input.base(); - } - jarout->addJarEntry(f->name, f->deflate_hint(), f->modtime, part1, part2); - } - if (verbose >= 3) - { - fprintf(stderr, "Wrote %" PRIu64 " bytes to: %s\n", fsize, f->name); - } -} diff --git a/libraries/pack200/src/unpack.h b/libraries/pack200/src/unpack.h deleted file mode 100644 index cc5dd60a..00000000 --- a/libraries/pack200/src/unpack.h +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#pragma once - -// Global Structures -struct jar; -struct gunzip; -struct band; -struct constant_pool; -struct entry; -struct cpindex; -struct inner_class; -struct value_stream; - -typedef int64_t (*read_input_fn_t)(unpacker *self, void *buf, int64_t minlen, int64_t maxlen); - -struct cpindex -{ - uint32_t len; - entry *base1; // base of primary index - entry **base2; // base of secondary index - byte ixTag; // type of entries (!= CONSTANT_None), plus 64 if sub-index - enum - { - SUB_TAG = 64 - }; - - entry *get(uint32_t i); - - void init(int len_, entry *base1_, int ixTag_) - { - len = len_; - base1 = base1_; - base2 = nullptr; - ixTag = ixTag_; - } - void init(int len_, entry **base2_, int ixTag_) - { - len = len_; - base1 = nullptr; - base2 = base2_; - ixTag = ixTag_; - } -}; - -struct constant_pool -{ - uint32_t nentries; - entry *entries; - entry *first_extra_entry; - uint32_t maxentries; // total allocated size of entries - - // Position and size of each homogeneous subrange: - int tag_count[CONSTANT_Limit]; - int tag_base[CONSTANT_Limit]; - cpindex tag_index[CONSTANT_Limit]; - ptrlist tag_extras[CONSTANT_Limit]; - - cpindex *member_indexes; // indexed by 2*CONSTANT_Class.inord - cpindex *getFieldIndex(entry *classRef); - cpindex *getMethodIndex(entry *classRef); - - inner_class **ic_index; - inner_class **ic_child_index; - inner_class *getIC(entry *inner); - inner_class *getFirstChildIC(entry *outer); - inner_class *getNextChildIC(inner_class *child); - - int outputIndexLimit; // index limit after renumbering - ptrlist outputEntries; // list of entry* needing output idx assigned - - entry **hashTab; - uint32_t hashTabLength; - entry *&hashTabRef(byte tag, bytes &b); - entry *ensureUtf8(bytes &b); - entry *ensureClass(bytes &b); - - // Well-known Utf8 symbols. - enum - { -#define SNAME(n, s) s_##s, - ALL_ATTR_DO(SNAME) -#undef SNAME - s_lt_init_gt, // - s_LIMIT - }; - entry *sym[s_LIMIT]; - - // read counts from hdr, allocate main arrays - enum - { - NUM_COUNTS = 12 - }; - void init(unpacker *u, int counts[NUM_COUNTS]); - - // pointer to outer unpacker, for error checks etc. - unpacker *u; - - int getCount(byte tag) - { - assert((uint32_t)tag < CONSTANT_Limit); - return tag_count[tag]; - } - cpindex *getIndex(byte tag) - { - assert((uint32_t)tag < CONSTANT_Limit); - return &tag_index[tag]; - } - cpindex *getKQIndex(); // uses cur_descr - - void expandSignatures(); - void initMemberIndexes(); - - void computeOutputOrder(); - void computeOutputIndexes(); - void resetOutputIndexes(); -}; - -/* - * The unpacker provides the entry points to the unpack engine, - * as well as maintains the state of the engine. - */ -struct unpacker -{ - // One element of the resulting JAR. - struct file - { - const char *name; - uint64_t size; - int modtime; - int options; - bytes data[2]; - // Note: If Sum(data[*].len) < size, - // remaining bytes must be read directly from the input stream. - bool deflate_hint() - { - return ((options & FO_DEFLATE_HINT) != 0); - } - }; - - // if running Unix-style, here are the inputs and outputs - FILE *infileptr; // buffered - bytes inbytes; // direct - gunzip *gzin; // gunzip filter, if any - jar *jarout; // output JAR file - - // pointer to self, for U_NEW macro - unpacker *u; - - ptrlist mallocs; // list of guys to free when we are all done - ptrlist tmallocs; // list of guys to free on next client request - fillbytes smallbuf; // supplies small alloc requests - fillbytes tsmallbuf; // supplies temporary small alloc requests - - // option management members - int verbose; // verbose level, 0 means no output - int deflate_hint_or_zero; // ==0 means not set, otherwise -1 or 1 - int modification_time_or_zero; - - // input stream - fillbytes input; // the whole block (size is predicted, has slop too) - bool live_input; // is the data in this block live? - bool free_input; // must the input buffer be freed? - byte *rp; // read pointer (< rplimit <= input.limit()) - byte *rplimit; // how much of the input block has been read? - uint64_t bytes_read; - int unsized_bytes_read; - - // callback to read at least one byte, up to available input - read_input_fn_t read_input_fn; - - // archive header fields - int magic, minver, majver; - size_t archive_size; - int archive_next_count, archive_options, archive_modtime; - int band_headers_size; - int file_count, attr_definition_count, ic_count, class_count; - int default_class_minver, default_class_majver; - int default_file_options, suppress_file_options; // not header fields - int default_archive_modtime, default_file_modtime; // not header fields - int code_count; // not a header field - int files_remaining; // not a header field - - // engine state - band *all_bands; // indexed by band_number - byte *meta_rp; // read-pointer into (copy of) band_headers - constant_pool cp; // all constant pool information - inner_class *ics; // InnerClasses - - // output stream - bytes output; // output block (either classfile head or tail) - byte *wp; // write pointer (< wplimit == output.limit()) - byte *wpbase; // write pointer starting address (<= wp) - byte *wplimit; // how much of the output block has been written? - - // output state - file cur_file; - entry *cur_class; // CONSTANT_Class entry - entry *cur_super; // CONSTANT_Class entry or nullptr - entry *cur_descr; // CONSTANT_NameandType entry - int cur_descr_flags; // flags corresponding to cur_descr - int cur_class_minver, cur_class_majver; - bool cur_class_has_local_ics; - fillbytes cur_classfile_head; - fillbytes cur_classfile_tail; - int files_written; // also tells which file we're working on - int classes_written; // also tells which class we're working on - uint64_t bytes_written; - intlist bcimap; - fillbytes class_fixup_type; - intlist class_fixup_offset; - ptrlist class_fixup_ref; - fillbytes code_fixup_type; // which format of branch operand? - intlist code_fixup_offset; // location of operand needing fixup - intlist code_fixup_source; // encoded ID of branch insn - ptrlist requested_ics; // which ics need output? - - // stats pertaining to multiple segments (updated on reset) - uint64_t bytes_read_before_reset; - uint64_t bytes_written_before_reset; - int files_written_before_reset; - int classes_written_before_reset; - int segments_read_before_reset; - - // attribute state - struct layout_definition - { - uint32_t idx; // index (0..31...) which identifies this layout - const char *name; // name of layout - entry *nameEntry; - const char *layout; // string of layout (not yet parsed) - band **elems; // array of top-level layout elems (or callables) - - bool hasCallables() - { - return layout[0] == '['; - } - band **bands() - { - assert(elems != nullptr); - return elems; - } - }; - struct attr_definitions - { - unpacker *u; // pointer to self, for U_NEW macro - int xxx_flags_hi_bn; // locator for flags, count, indexes, calls bands - int attrc; // ATTR_CONTEXT_CLASS, etc. - uint32_t flag_limit; // 32 or 63, depending on archive_options bit - uint64_t predef; // mask of built-in definitions - uint64_t redef; // mask of local flag definitions or redefinitions - ptrlist layouts; // local (compressor-defined) defs, in index order - int flag_count[X_ATTR_LIMIT_FLAGS_HI]; - intlist overflow_count; - ptrlist strip_names; // what attribute names are being stripped? - ptrlist band_stack; // Temp., used during layout parsing. - ptrlist calls_to_link; // (ditto) - int bands_made; // (ditto) - - void free() - { - layouts.free(); - overflow_count.free(); - strip_names.free(); - band_stack.free(); - calls_to_link.free(); - } - - // Locate the five fixed bands. - band &xxx_flags_hi(); - band &xxx_flags_lo(); - band &xxx_attr_count(); - band &xxx_attr_indexes(); - band &xxx_attr_calls(); - band &fixed_band(int e_class_xxx); - - // Register a new layout, and make bands for it. - layout_definition *defineLayout(int idx, const char *name, const char *layout); - layout_definition *defineLayout(int idx, entry *nameEntry, const char *layout); - band **buildBands(layout_definition *lo); - - // Parse a layout string or part of one, recursively if necessary. - const char *parseLayout(const char *lp, band **&res, int curCble); - const char *parseNumeral(const char *lp, int &res); - const char *parseIntLayout(const char *lp, band *&res, byte le_kind, - bool can_be_signed = false); - band **popBody(int band_stack_base); // pops a body off band_stack - - // Read data into the bands of the idx-th layout. - void readBandData(int idx); // parse layout, make bands, read data - void readBandData(band **body, uint32_t count); // recursive helper - - layout_definition *getLayout(uint32_t idx) - { - if (idx >= (uint32_t)layouts.length()) - return nullptr; - return (layout_definition *)layouts.get(idx); - } - - void setHaveLongFlags(bool z) - { - assert(flag_limit == 0); // not set up yet - flag_limit = (z ? X_ATTR_LIMIT_FLAGS_HI : X_ATTR_LIMIT_NO_FLAGS_HI); - } - bool haveLongFlags() - { - assert(flag_limit == X_ATTR_LIMIT_NO_FLAGS_HI || - flag_limit == X_ATTR_LIMIT_FLAGS_HI); - return flag_limit == X_ATTR_LIMIT_FLAGS_HI; - } - - // Return flag_count if idx is predef and not redef, else zero. - int predefCount(uint32_t idx); - - bool isRedefined(uint32_t idx) - { - if (idx >= flag_limit) - return false; - return (bool)((redef >> idx) & 1); - } - bool isPredefined(uint32_t idx) - { - if (idx >= flag_limit) - return false; - return (bool)(((predef & ~redef) >> idx) & 1); - } - uint64_t flagIndexMask() - { - return (predef | redef); - } - bool isIndex(uint32_t idx) - { - assert(flag_limit != 0); // must be set up already - if (idx < flag_limit) - return (bool)(((predef | redef) >> idx) & 1); - else - return (idx - flag_limit < (uint32_t)overflow_count.length()); - } - int &getCount(uint32_t idx) - { - assert(isIndex(idx)); - if (idx < flag_limit) - return flag_count[idx]; - else - return overflow_count.get(idx - flag_limit); - } - }; - - attr_definitions attr_defs[ATTR_CONTEXT_LIMIT]; - - // Initialization - void init(read_input_fn_t input_fn = nullptr); - // Resets to a known sane state - void reset(); - // Deallocates all storage. - void free(); - // Deallocates temporary storage (volatile after next client call). - void free_temps() - { - tsmallbuf.init(); - tmallocs.freeAll(); - } - - // Option management methods - bool set_option(const char *option, const char *value); - const char *get_option(const char *option); - - // Fetching input. - bool ensure_input(int64_t more); - byte *input_scan() - { - return rp; - } - size_t input_remaining() - { - return rplimit - rp; - } - size_t input_consumed() - { - return rp - input.base(); - } - - // Entry points to the unpack engine - static int run(int argc, char **argv); // Unix-style entry point. - void check_options(); - void start(void *packptr = nullptr, size_t len = 0); - void write_file_to_jar(file *f); - void finish(); - - // Public post unpack methods - int get_files_remaining() - { - return files_remaining; - } - int get_segments_remaining() - { - return archive_next_count; - } - file *get_next_file(); // returns nullptr on last file - - // General purpose methods - void *alloc(size_t size) - { - return alloc_heap(size, true); - } - void *temp_alloc(size_t size) - { - return alloc_heap(size, true, true); - } - void *alloc_heap(size_t size, bool smallOK = false, bool temp = false); - void saveTo(bytes &b, const char *str) - { - saveTo(b, (byte *)str, strlen(str)); - } - void saveTo(bytes &b, bytes &data) - { - saveTo(b, data.ptr, data.len); - } - void saveTo(bytes &b, byte *ptr, size_t len); //{ b.ptr = U_NEW...} - const char *saveStr(const char *str) - { - bytes buf; - saveTo(buf, str); - return buf.strval(); - } - const char *saveIntStr(int num) - { - char buf[30]; - sprintf(buf, "%d", num); - return saveStr(buf); - } - static unpacker *current(); // find current instance - - // Output management - void set_output(fillbytes *which) - { - assert(wp == nullptr); - which->ensureSize(1 << 12); // covers the average classfile - wpbase = which->base(); - wp = which->limit(); - wplimit = which->end(); - } - fillbytes *close_output(fillbytes *which = nullptr); // inverse of set_output - - // These take an implicit parameter of wp/wplimit, and resize as necessary: - byte *put_space(size_t len); // allocates space at wp, returns pointer - size_t put_empty(size_t s) - { - byte *p = put_space(s); - return p - wpbase; - } - void ensure_put_space(size_t len); - void put_bytes(bytes &b) - { - b.writeTo(put_space(b.len)); - } - void putu1(int n) - { - putu1_at(put_space(1), n); - } - void putu1_fast(int n) - { - putu1_at(wp++, n); - } - void putu2(int n); // { putu2_at(put_space(2), n); } - void putu4(int n); // { putu4_at(put_space(4), n); } - void putu8(int64_t n); // { putu8_at(put_space(8), n); } - void putref(entry *e); // { putu2_at(put_space(2), putref_index(e, 2)); } - void putu1ref(entry *e); // { putu1_at(put_space(1), putref_index(e, 1)); } - int putref_index(entry *e, int size); // size in [1..2] - void put_label(int curIP, int size); // size in {2,4} - void putlayout(band **body); - void put_stackmap_type(); - - size_t wpoffset() - { - return (size_t)(wp - wpbase); - } // (unvariant across overflow) - byte *wp_at(size_t offset) - { - return wpbase + offset; - } - uint32_t to_bci(uint32_t bii); - void get_code_header(int &max_stack, int &max_na_locals, int &handler_count, int &cflags); - band *ref_band_for_self_op(int bc, bool &isAloadVar, int &origBCVar); - band *ref_band_for_op(int bc); - - // Definitions of standard classfile int formats: - static void putu1_at(byte *wp, int n) - { - assert(n == (n & 0xFF)); - wp[0] = n; - } - static void putu2_at(byte *wp, int n); - static void putu4_at(byte *wp, int n); - static void putu8_at(byte *wp, int64_t n); - - // Private stuff - void reset_cur_classfile(); - void write_classfile_tail(); - void write_classfile_head(); - void write_code(); - void write_bc_ops(); - void write_members(int num, int attrc); // attrc=ATTR_CONTEXT_FIELD/METHOD - int write_attrs(int attrc, uint64_t indexBits); - - // The readers - void read_bands(); - void read_file_header(); - void read_cp(); - void read_cp_counts(value_stream &hdr); - void read_attr_defs(); - void read_ics(); - void read_attrs(int attrc, int obj_count); - void read_classes(); - void read_code_headers(); - void read_bcs(); - void read_bc_ops(); - void read_files(); - void read_Utf8_values(entry *cpMap, int len); - void read_single_words(band &cp_band, entry *cpMap, int len); - void read_double_words(band &cp_bands, entry *cpMap, int len); - void read_single_refs(band &cp_band, byte refTag, entry *cpMap, int len); - void read_double_refs(band &cp_band, byte ref1Tag, byte ref2Tag, entry *cpMap, int len); - void read_signature_values(entry *cpMap, int len); -}; diff --git a/libraries/pack200/src/unpack200.cpp b/libraries/pack200/src/unpack200.cpp deleted file mode 100644 index e8826f28..00000000 --- a/libraries/pack200/src/unpack200.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "utils.h" -#include "defines.h" -#include "bytes.h" -#include "coding.h" -#include "unpack200.h" -#include "unpack.h" -#include "zip.h" - -// Callback for fetching data, Unix style. -static int64_t read_input_via_stdio(unpacker *u, void *buf, int64_t minlen, int64_t maxlen) -{ - assert(u->infileptr != nullptr); - assert(minlen <= maxlen); // don't talk nonsense - int64_t numread = 0; - char *bufptr = (char *)buf; - while (numread < minlen) - { - // read available input, up to buf.length or maxlen - int readlen = (1 << 16); - if (readlen > (maxlen - numread)) - readlen = (int)(maxlen - numread); - int nr = 0; - - nr = (int)fread(bufptr, 1, readlen, u->infileptr); - if (nr <= 0) - { - if (errno != EINTR) - break; - nr = 0; - } - numread += nr; - bufptr += nr; - assert(numread <= maxlen); - } - return numread; -} - -enum -{ - EOF_MAGIC = 0, - BAD_MAGIC = -1 -}; - -static int read_magic(unpacker *u, char peek[], int peeklen) -{ - assert(peeklen == 4); // magic numbers are always 4 bytes - int64_t nr = (u->read_input_fn)(u, peek, peeklen, peeklen); - if (nr != peeklen) - { - return (nr == 0) ? EOF_MAGIC : BAD_MAGIC; - } - int magic = 0; - for (int i = 0; i < peeklen; i++) - { - magic <<= 8; - magic += peek[i] & 0xFF; - } - return magic; -} - -void unpack_200(FILE *input, FILE *output) -{ - unpacker u; - u.init(read_input_via_stdio); - - // initialize jar output - // the output takes ownership of the file handle - jar jarout; - jarout.init(&u); - jarout.jarfp = output; - - // the input doesn't - u.infileptr = input; - - // read the magic! - char peek[4]; - int magic; - magic = read_magic(&u, peek, (int)sizeof(peek)); - - // if it is a gzip encoded file, we need an extra gzip input filter - if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC) - { - gunzip *gzin = NEW(gunzip, 1); - gzin->init(&u); - // FIXME: why the side effects? WHY? - u.gzin->start(magic); - u.start(); - } - else - { - // otherwise, feed the bytes to the unpacker directly - u.start(peek, sizeof(peek)); - } - - // Note: The checks to u.aborting() are necessary to gracefully - // terminate processing when the first segment throws an error. - for (;;) - { - // Each trip through this loop unpacks one segment - // and then resets the unpacker. - for (unpacker::file *filep; (filep = u.get_next_file()) != nullptr;) - { - u.write_file_to_jar(filep); - } - - // Peek ahead for more data. - magic = read_magic(&u, peek, (int)sizeof(peek)); - if (magic != (int)JAVA_PACKAGE_MAGIC) - { - // we do not feel strongly about this kind of thing... - /* - if (magic != EOF_MAGIC) - unpack_abort("garbage after end of pack archive"); - */ - break; // all done - } - - // Release all storage from parsing the old segment. - u.reset(); - // Restart, beginning with the peek-ahead. - u.start(peek, sizeof(peek)); - } - u.finish(); - u.free(); // tidy up malloc blocks - fclose(input); -} diff --git a/libraries/pack200/src/utils.cpp b/libraries/pack200/src/utils.cpp deleted file mode 100644 index fd6dad60..00000000 --- a/libraries/pack200/src/utils.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef _MSC_VER -#include -#include -#include -#else -#include -#endif - -#include "constants.h" -#include "defines.h" -#include "bytes.h" -#include "utils.h" - -#include "unpack.h" - -void *must_malloc(size_t size) -{ - size_t msize = size; - void *ptr = (msize > PSIZE_MAX) ? nullptr : malloc(msize); - if (ptr != nullptr) - { - memset(ptr, 0, size); - } - else - { - throw std::runtime_error(ERROR_ENOMEM); - } - return ptr; -} - -void unpack_abort(const char *msg) -{ - if (msg == nullptr) - msg = "corrupt pack file or internal error"; - throw std::runtime_error(msg); -} diff --git a/libraries/pack200/src/utils.h b/libraries/pack200/src/utils.h deleted file mode 100644 index 3bd2dae7..00000000 --- a/libraries/pack200/src/utils.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// Definitions of our util functions - -#include - -void *must_malloc(size_t size); - -// overflow management -#define OVERFLOW ((size_t) - 1) -#define PSIZE_MAX (OVERFLOW / 2) /* normal size limit */ - -inline size_t scale_size(size_t size, size_t scale) -{ - return (size > PSIZE_MAX / scale) ? OVERFLOW : size * scale; -} - -inline size_t add_size(size_t size1, size_t size2) -{ - return ((size1 | size2 | (size1 + size2)) > PSIZE_MAX) ? OVERFLOW : size1 + size2; -} - -inline size_t add_size(size_t size1, size_t size2, int size3) -{ - return add_size(add_size(size1, size2), size3); -} - -struct unpacker; -/// This throws an exception! -extern void unpack_abort(const char *msg = nullptr); diff --git a/libraries/pack200/src/zip.cpp b/libraries/pack200/src/zip.cpp deleted file mode 100644 index e776510b..00000000 --- a/libraries/pack200/src/zip.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Note: Lifted from uncrunch.c from jdk sources - */ -#include -#include -#include -#include -#include - -#include -#include - -#ifndef _MSC_VER -#include -#endif - -#include "defines.h" -#include "bytes.h" -#include "utils.h" - -#include "constants.h" -#include "unpack.h" - -#include "zip.h" - -#include "zlib.h" - -inline uint32_t jar::get_crc32(uint32_t c, uchar *ptr, uint32_t len) -{ - return crc32(c, ptr, len); -} - -// FIXME: this is bullshit. Do real endianness detection. -#ifdef sparc -#define SWAP_BYTES(a) ((((a) << 8) & 0xff00) | 0x00ff) & (((a) >> 8) | 0xff00) -#else -#define SWAP_BYTES(a) (a) -#endif - -#define GET_INT_LO(a) SWAP_BYTES(a & 0xFFFF) - -#define GET_INT_HI(a) SWAP_BYTES((a >> 16) & 0xFFFF); - -void jar::init(unpacker *u_) -{ - BYTES_OF(*this).clear(); - u = u_; - u->jarout = this; -} - -// Write data to the ZIP output stream. -void jar::write_data(void *buff, int len) -{ - while (len > 0) - { - int rc = (int)fwrite(buff, 1, len, jarfp); - if (rc <= 0) - { - fprintf(stderr, "Error: write on output file failed err=%d\n", errno); - exit(1); // Called only from the native standalone unpacker - } - output_file_offset += rc; - buff = ((char *)buff) + rc; - len -= rc; - } -} - -void jar::add_to_jar_directory(const char *fname, bool store, int modtime, int len, int clen, - uint32_t crc) -{ - uint32_t fname_length = (uint32_t)strlen(fname); - ushort header[23]; - if (modtime == 0) - modtime = default_modtime; - uint32_t dostime = get_dostime(modtime); - - header[0] = (ushort)SWAP_BYTES(0x4B50); - header[1] = (ushort)SWAP_BYTES(0x0201); - header[2] = (ushort)SWAP_BYTES(0xA); - - // required version - header[3] = (ushort)SWAP_BYTES(0xA); - - // flags 02 = maximum sub-compression flag - header[4] = (store) ? 0x0 : SWAP_BYTES(0x2); - - // Compression method 8=deflate. - header[5] = (store) ? 0x0 : SWAP_BYTES(0x08); - - // Last modified date and time. - header[6] = (ushort)GET_INT_LO(dostime); - header[7] = (ushort)GET_INT_HI(dostime); - - // CRC - header[8] = (ushort)GET_INT_LO(crc); - header[9] = (ushort)GET_INT_HI(crc); - - // Compressed length: - header[10] = (ushort)GET_INT_LO(clen); - header[11] = (ushort)GET_INT_HI(clen); - - // Uncompressed length. - header[12] = (ushort)GET_INT_LO(len); - header[13] = (ushort)GET_INT_HI(len); - - // Filename length - header[14] = (ushort)SWAP_BYTES(fname_length); - // So called "extra field" length. - header[15] = 0; - // So called "comment" length. - header[16] = 0; - // Disk number start - header[17] = 0; - // File flags => binary - header[18] = 0; - // More file flags - header[19] = 0; - header[20] = 0; - // Offset within ZIP file. - header[21] = (ushort)GET_INT_LO(output_file_offset); - header[22] = (ushort)GET_INT_HI(output_file_offset); - - // Copy the whole thing into the central directory. - central_directory.append(header, sizeof(header)); - - // Copy the fname to the header. - central_directory.append(fname, fname_length); - - central_directory_count++; -} - -void jar::write_jar_header(const char *fname, bool store, int modtime, int len, int clen, - uint32_t crc) -{ - uint32_t fname_length = (uint32_t)strlen(fname); - ushort header[15]; - if (modtime == 0) - modtime = default_modtime; - uint32_t dostime = get_dostime(modtime); - - // ZIP LOC magic. - header[0] = (ushort)SWAP_BYTES(0x4B50); - header[1] = (ushort)SWAP_BYTES(0x0403); - - // Version - header[2] = (ushort)SWAP_BYTES(0xA); - - // flags 02 = maximum sub-compression flag - header[3] = (store) ? 0x0 : SWAP_BYTES(0x2); - - // Compression method = deflate - header[4] = (store) ? 0x0 : SWAP_BYTES(0x08); - - // Last modified date and time. - header[5] = (ushort)GET_INT_LO(dostime); - header[6] = (ushort)GET_INT_HI(dostime); - - // CRC - header[7] = (ushort)GET_INT_LO(crc); - header[8] = (ushort)GET_INT_HI(crc); - - // Compressed length: - header[9] = (ushort)GET_INT_LO(clen); - header[10] = (ushort)GET_INT_HI(clen); - - // Uncompressed length. - header[11] = (ushort)GET_INT_LO(len); - header[12] = (ushort)GET_INT_HI(len); - - // Filename length - header[13] = (ushort)SWAP_BYTES(fname_length); - // So called "extra field" length. - header[14] = 0; - - // Write the LOC header to the output file. - write_data(header, (int)sizeof(header)); - - // Copy the fname to the header. - write_data((char *)fname, (int)fname_length); -} - -void jar::write_central_directory() -{ - bytes mc; - mc.set("PACK200"); - - ushort header[11]; - - // Create the End of Central Directory structure. - header[0] = (ushort)SWAP_BYTES(0x4B50); - header[1] = (ushort)SWAP_BYTES(0x0605); - // disk numbers - header[2] = 0; - header[3] = 0; - // Number of entries in central directory. - header[4] = (ushort)SWAP_BYTES(central_directory_count); - header[5] = (ushort)SWAP_BYTES(central_directory_count); - // Size of the central directory} - header[6] = (ushort)GET_INT_LO((int)central_directory.size()); - header[7] = (ushort)GET_INT_HI((int)central_directory.size()); - // Offset of central directory within disk. - header[8] = (ushort)GET_INT_LO(output_file_offset); - header[9] = (ushort)GET_INT_HI(output_file_offset); - // zipfile comment length; - header[10] = (ushort)SWAP_BYTES((int)mc.len); - - // Write the central directory. - write_data(central_directory.b); - - // Write the End of Central Directory structure. - write_data(header, (int)sizeof(header)); - - // Write the comment. - write_data(mc); -} - -// Public API - -// Open a Jar file and initialize. -void jar::openJarFile(const char *fname) -{ - if (!jarfp) - { - jarfp = fopen(fname, "wb"); - if (!jarfp) - { - fprintf(stderr, "Error: Could not open jar file: %s\n", fname); - exit(3); // Called only from the native standalone unpacker - } - } -} - -// Add a ZIP entry and copy the file data -void jar::addJarEntry(const char *fname, bool deflate_hint, int modtime, bytes &head, - bytes &tail) -{ - int len = (int)(head.len + tail.len); - int clen = 0; - - uint32_t crc = get_crc32(0, Z_NULL, 0); - if (head.len != 0) - crc = get_crc32(crc, (uchar *)head.ptr, (uint32_t)head.len); - if (tail.len != 0) - crc = get_crc32(crc, (uchar *)tail.ptr, (uint32_t)tail.len); - - bool deflate = (deflate_hint && len > 0); - - if (deflate) - { - if (deflate_bytes(head, tail) == false) - { - deflate = false; - } - } - clen = (int)((deflate) ? deflated.size() : len); - add_to_jar_directory(fname, !deflate, modtime, len, clen, crc); - write_jar_header(fname, !deflate, modtime, len, clen, crc); - - if (deflate) - { - write_data(deflated.b); - } - else - { - write_data(head); - write_data(tail); - } -} - -// Add a ZIP entry for a directory name no data -void jar::addDirectoryToJarFile(const char *dir_name) -{ - bool store = true; - add_to_jar_directory((const char *)dir_name, store, default_modtime, 0, 0, 0); - write_jar_header((const char *)dir_name, store, default_modtime, 0, 0, 0); -} - -// Write out the central directory and close the jar file. -void jar::closeJarFile(bool central) -{ - if (jarfp) - { - fflush(jarfp); - if (central) - write_central_directory(); - fflush(jarfp); - fclose(jarfp); - } - reset(); -} - -/* Convert the date y/n/d and time h:m:s to a four byte DOS date and - * time (date in high two bytes, time in low two bytes allowing magnitude - * comparison). - */ -inline uint32_t jar::dostime(int y, int n, int d, int h, int m, int s) -{ - return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) - : (((uint32_t)y - 1980) << 25) | ((uint32_t)n << 21) | ((uint32_t)d << 16) | - ((uint32_t)h << 11) | ((uint32_t)m << 5) | ((uint32_t)s >> 1); -} -/* -#ifdef _REENTRANT // solaris -extern "C" struct tm *gmtime_r(const time_t *, struct tm *); -#else -#define gmtime_r(t, s) gmtime(t) -#endif -*/ -/* - * Return the Unix time in DOS format - */ -uint32_t jar::get_dostime(int modtime) -{ - // see defines.h - if (modtime != 0 && modtime == modtime_cache) - return dostime_cache; - if (modtime != 0 && default_modtime == 0) - default_modtime = modtime; // catch a reasonable default - time_t t = modtime; - struct tm sbuf; - (void)memset((void *)&sbuf, 0, sizeof(sbuf)); - struct tm *s = gmtime_r(&t, &sbuf); - modtime_cache = modtime; - dostime_cache = - dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday, s->tm_hour, s->tm_min, s->tm_sec); - // printf("modtime %d => %d\n", modtime_cache, dostime_cache); - return dostime_cache; -} - -/* Returns true on success, and will set the clen to the compressed - length, the caller should verify if true and clen less than the - input data -*/ -bool jar::deflate_bytes(bytes &head, bytes &tail) -{ - int len = (int)(head.len + tail.len); - - z_stream zs; - BYTES_OF(zs).clear(); - - // NOTE: the window size should always be -MAX_WBITS normally -15. - // unzip/zipup.c and java/Deflater.c - - int error = - deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); - if (error != Z_OK) - { - /* - switch (error) - { - case Z_MEM_ERROR: - PRINTCR((2, "Error: deflate error : Out of memory \n")); - break; - case Z_STREAM_ERROR: - PRINTCR((2, "Error: deflate error : Invalid compression level \n")); - break; - case Z_VERSION_ERROR: - PRINTCR((2, "Error: deflate error : Invalid version\n")); - break; - default: - PRINTCR((2, "Error: Internal deflate error error = %d\n", error)); - } - */ - return false; - } - - deflated.empty(); - zs.next_out = (uchar *)deflated.grow(len + (len / 2)); - zs.avail_out = (int)deflated.size(); - - zs.next_in = (uchar *)head.ptr; - zs.avail_in = (int)head.len; - - bytes *first = &head; - bytes *last = &tail; - if (last->len == 0) - { - first = nullptr; - last = &head; - } - else if (first->len == 0) - { - first = nullptr; - } - - if (first != nullptr && error == Z_OK) - { - zs.next_in = (uchar *)first->ptr; - zs.avail_in = (int)first->len; - error = deflate(&zs, Z_NO_FLUSH); - } - if (error == Z_OK) - { - zs.next_in = (uchar *)last->ptr; - zs.avail_in = (int)last->len; - error = deflate(&zs, Z_FINISH); - } - if (error == Z_STREAM_END) - { - if (len > (int)zs.total_out) - { - deflated.b.len = zs.total_out; - deflateEnd(&zs); - return true; - } - deflateEnd(&zs); - return false; - } - - deflateEnd(&zs); - return false; -} - -// Callback for fetching data from a GZIP input stream -static int64_t read_input_via_gzip(unpacker *u, void *buf, int64_t minlen, int64_t maxlen) -{ - assert(minlen <= maxlen); // don't talk nonsense - int64_t numread = 0; - char *bufptr = (char *)buf; - char *inbuf = u->gzin->inbuf; - size_t inbuflen = sizeof(u->gzin->inbuf); - read_input_fn_t read_gzin_fn = u->gzin->read_input_fn; - z_stream &zs = *(z_stream *)u->gzin->zstream; - while (numread < minlen) - { - int readlen = (1 << 16); // pretty arbitrary - if (readlen > (maxlen - numread)) - readlen = (int)(maxlen - numread); - zs.next_out = (uchar *)bufptr; - zs.avail_out = readlen; - if (zs.avail_in == 0) - { - zs.avail_in = (int)read_gzin_fn(u, inbuf, 1, inbuflen); - zs.next_in = (uchar *)inbuf; - } - int error = inflate(&zs, Z_NO_FLUSH); - if (error != Z_OK && error != Z_STREAM_END) - { - unpack_abort("error inflating input"); - break; - } - int nr = readlen - zs.avail_out; - numread += nr; - bufptr += nr; - assert(numread <= maxlen); - if (error == Z_STREAM_END) - { - enum - { - TRAILER_LEN = 8 - }; - // skip 8-byte trailer - if (zs.avail_in >= TRAILER_LEN) - { - zs.avail_in -= TRAILER_LEN; - } - else - { - // Bug: 5023768,we read past the TRAILER_LEN to see if there is - // any extraneous data, as we dont support concatenated .gz - // files just yet. - int extra = (int)read_gzin_fn(u, inbuf, 1, inbuflen); - zs.avail_in += extra - TRAILER_LEN; - } - // %%% should check final CRC and length here - // %%% should check for concatenated *.gz files here - if (zs.avail_in > 0) - unpack_abort("garbage after end of deflated input stream"); - // pop this filter off: - u->gzin->free(); - break; - } - } - - // fprintf(u->errstrm, "readInputFn(%d,%d) => %d (gunzip)\n", - // (int)minlen, (int)maxlen, (int)numread); - return numread; -} - -void gunzip::init(unpacker *u_) -{ - BYTES_OF(*this).clear(); - u = u_; - assert(u->gzin == nullptr); // once only, please - read_input_fn = u->read_input_fn; - zstream = NEW(z_stream, 1); - u->gzin = this; - u->read_input_fn = read_input_via_gzip; -} - -void gunzip::start(int magic) -{ - assert((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC); - int gz_flg = (magic & 0xFF); // keep "flg", discard other 3 bytes - enum - { - FHCRC = (1 << 1), - FEXTRA = (1 << 2), - FNAME = (1 << 3), - FCOMMENT = (1 << 4) - }; - char gz_mtime[4]; - char gz_xfl[1]; - char gz_os[1]; - char gz_extra_len[2]; - char gz_hcrc[2]; - char gz_ignore; - // do not save extra, name, comment - read_fixed_field(gz_mtime, sizeof(gz_mtime)); - read_fixed_field(gz_xfl, sizeof(gz_xfl)); - read_fixed_field(gz_os, sizeof(gz_os)); - if (gz_flg & FEXTRA) - { - read_fixed_field(gz_extra_len, sizeof(gz_extra_len)); - int extra_len = gz_extra_len[0] & 0xFF; - extra_len += (gz_extra_len[1] & 0xFF) << 8; - for (; extra_len > 0; extra_len--) - { - read_fixed_field(&gz_ignore, 1); - } - } - int null_terms = 0; - if (gz_flg & FNAME) - null_terms++; - if (gz_flg & FCOMMENT) - null_terms++; - for (; null_terms; null_terms--) - { - for (;;) - { - gz_ignore = 0; - read_fixed_field(&gz_ignore, 1); - if (gz_ignore == 0) - break; - } - } - if (gz_flg & FHCRC) - read_fixed_field(gz_hcrc, sizeof(gz_hcrc)); - - // now the input stream is ready to read into the inflater - int error = inflateInit2((z_stream *)zstream, -MAX_WBITS); - if (error != Z_OK) - { - unpack_abort("cannot create input"); - } -} - -void gunzip::free() -{ - assert(u->gzin == this); - u->gzin = nullptr; - u->read_input_fn = this->read_input_fn; - inflateEnd((z_stream *)zstream); - ::free(zstream); - zstream = nullptr; - ::free(this); -} - -void gunzip::read_fixed_field(char *buf, size_t buflen) -{ - int64_t nr = read_input_fn(u, buf, buflen, buflen); - if ((size_t)nr != buflen) - unpack_abort("short stream header"); -} diff --git a/libraries/pack200/src/zip.h b/libraries/pack200/src/zip.h deleted file mode 100644 index ff973a86..00000000 --- a/libraries/pack200/src/zip.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -#pragma once - -#include -typedef unsigned short ushort; -typedef unsigned int uint32_t; -typedef unsigned char uchar; - -#include "unpack.h" - -struct jar -{ - // JAR file writer - FILE *jarfp; - int default_modtime; - - // Used by unix2dostime: - int modtime_cache; - uint32_t dostime_cache; - - // Private members - fillbytes central_directory; - ushort central_directory_count; - uint32_t output_file_offset; - fillbytes deflated; // temporary buffer - - // pointer to outer unpacker, for error checks etc. - unpacker *u; - - // Public Methods - void openJarFile(const char *fname); - void addJarEntry(const char *fname, bool deflate_hint, int modtime, bytes &head, - bytes &tail); - void addDirectoryToJarFile(const char *dir_name); - void closeJarFile(bool central); - - void init(unpacker *u_); - - void free() - { - central_directory.free(); - deflated.free(); - } - - void reset() - { - free(); - init(u); - } - - // Private Methods - void write_data(void *ptr, int len); - void write_data(bytes &b) - { - write_data(b.ptr, (int)b.len); - } - void add_to_jar_directory(const char *fname, bool store, int modtime, int len, int clen, - uint32_t crc); - void write_jar_header(const char *fname, bool store, int modtime, int len, int clen, - unsigned int crc); - void write_central_directory(); - uint32_t dostime(int y, int n, int d, int h, int m, int s); - uint32_t get_dostime(int modtime); - - // The definitions of these depend on the NO_ZLIB option: - bool deflate_bytes(bytes &head, bytes &tail); - static uint32_t get_crc32(uint32_t c, unsigned char *ptr, uint32_t len); -}; - -struct gunzip -{ - // optional gzip input stream control block - - // pointer to outer unpacker, for error checks etc. - unpacker *u; - - read_input_fn_t read_input_fn; // underlying \bchar\b stream - void *zstream; // inflater state - char inbuf[1 << 14]; // input buffer - - void init(unpacker *u_); // pushes new value on u->read_input_fn - - void free(); - - void start(int magic); - - // private stuff - void read_fixed_field(char *buf, size_t buflen); -}; From ba6a97557a0d90d77e9eba560931414e39042447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 28 May 2020 23:17:50 +0200 Subject: [PATCH 09/12] NOISSUE prevent evil from winning --- CMakeLists.txt | 11 ++++++++++- application/MultiMC.cpp | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 747ec5c8..11b6b63f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,15 @@ cmake_minimum_required(VERSION 3.1) string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD) if(IS_IN_SOURCE_BUILD) - message(AUTHOR_WARNING "You are building MultiMC in-source. This is NOT recommended!") + message(FATAL_ERROR "You are building MultiMC in-source. Please separate the build tree from the source tree.") +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_HOST_SYSTEM_VERSION MATCHES ".*[Mm]icrosoft.*" OR + CMAKE_HOST_SYSTEM_VERSION MATCHES ".*WSL.*" + ) + message(FATAL_ERROR "This is not a supported environment for any purpose and should never be used.") + endif() endif() if(WIN32) @@ -13,6 +21,7 @@ endif() project(MultiMC) enable_testing() + ##################################### Set CMake options ##################################### set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 393ea046..6ab3ad26 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -146,6 +146,28 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) startTime = QDateTime::currentDateTime(); +#ifdef Q_OS_LINUX + { + QFile osrelease("/proc/sys/kernel/osrelease"); + if (osrelease.open(QFile::ReadOnly | QFile::Text)) { + QTextStream in(&osrelease); + auto contents = in.readAll(); + if( + contents.contains("WSL", Qt::CaseInsensitive) || + contents.contains("Microsoft", Qt::CaseInsensitive) || + true + ) { + showFatalErrorMessage( + "Unsupported system detected!", + "It seems you are supporting the exploitation of Free Software.\n\n" + "You smell bad and you should feel bad." + ); + return; + } + } + } +#endif + // Don't quit on hiding the last window this->setQuitOnLastWindowClosed(false); From 07a1052c69a7c7d7feedd878e3371d80c6143981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 28 May 2020 23:31:50 +0200 Subject: [PATCH 10/12] Fix. --- application/MultiMC.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 6ab3ad26..9897d02b 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -154,8 +154,7 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) auto contents = in.readAll(); if( contents.contains("WSL", Qt::CaseInsensitive) || - contents.contains("Microsoft", Qt::CaseInsensitive) || - true + contents.contains("Microsoft", Qt::CaseInsensitive) ) { showFatalErrorMessage( "Unsupported system detected!", From 0047ca454f9acc2e15a723454b1eac8a18b81904 Mon Sep 17 00:00:00 2001 From: Thalia Nero Date: Thu, 28 May 2020 17:59:54 -0400 Subject: [PATCH 11/12] Clarify WSL error messages --- CMakeLists.txt | 2 +- application/MultiMC.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11b6b63f..fdc61c06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_HOST_SYSTEM_VERSION MATCHES ".*[Mm]icrosoft.*" OR CMAKE_HOST_SYSTEM_VERSION MATCHES ".*WSL.*" ) - message(FATAL_ERROR "This is not a supported environment for any purpose and should never be used.") + message(FATAL_ERROR "Building MultiMC is not supported in Linux-on-Windows distributions.") endif() endif() diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 9897d02b..53044c51 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -158,8 +158,8 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv) ) { showFatalErrorMessage( "Unsupported system detected!", - "It seems you are supporting the exploitation of Free Software.\n\n" - "You smell bad and you should feel bad." + "Linux-on-Windows distributions are not supported.\n\n" + "Please use the Windows MultiMC binary when playing on Windows." ); return; } From 79208a738347805ec31e33e461ba76ce681f57d0 Mon Sep 17 00:00:00 2001 From: kb1000 Date: Sat, 30 May 2020 15:32:38 +0200 Subject: [PATCH 12/12] Allow compiling MultiMC using Qt builds without accessibility again --- application/MainWindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 34ffc54b..48b9ed47 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -578,7 +578,9 @@ public: MainWindow->resize(800, 600); MainWindow->setWindowIcon(MMC->getThemedIcon("logo")); MainWindow->setWindowTitle("MultiMC 5"); +#ifndef QT_NO_ACCESSIBILITY MainWindow->setAccessibleName("MultiMC"); +#endif createMainToolbar(MainWindow);