NOISSUE tabs -> spaces
This commit is contained in:
@ -12,15 +12,15 @@ include/LocalPeer.h
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND SINGLE_SOURCES
|
||||
src/LockedFile_unix.cpp
|
||||
)
|
||||
list(APPEND SINGLE_SOURCES
|
||||
src/LockedFile_unix.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SINGLE_SOURCES
|
||||
src/LockedFile_win.cpp
|
||||
)
|
||||
list(APPEND SINGLE_SOURCES
|
||||
src/LockedFile_win.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(LocalPeer STATIC ${SINGLE_SOURCES})
|
||||
|
@ -50,51 +50,51 @@ class LockedFile;
|
||||
class ApplicationId
|
||||
{
|
||||
public: /* methods */
|
||||
// traditional app = installed system wide and used in a multi-user environment
|
||||
static ApplicationId fromTraditionalApp();
|
||||
// ID based on a path with all the application data (no two instances with the same data path should run)
|
||||
static ApplicationId fromPathAndVersion(const QString & dataPath, const QString & version);
|
||||
// custom ID
|
||||
static ApplicationId fromCustomId(const QString & id);
|
||||
// custom ID, based on a raw string previously acquired from 'toString'
|
||||
static ApplicationId fromRawString(const QString & id);
|
||||
// traditional app = installed system wide and used in a multi-user environment
|
||||
static ApplicationId fromTraditionalApp();
|
||||
// ID based on a path with all the application data (no two instances with the same data path should run)
|
||||
static ApplicationId fromPathAndVersion(const QString & dataPath, const QString & version);
|
||||
// custom ID
|
||||
static ApplicationId fromCustomId(const QString & id);
|
||||
// custom ID, based on a raw string previously acquired from 'toString'
|
||||
static ApplicationId fromRawString(const QString & id);
|
||||
|
||||
|
||||
QString toString()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
QString toString()
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
private: /* methods */
|
||||
ApplicationId(const QString & value)
|
||||
{
|
||||
m_id = value;
|
||||
}
|
||||
ApplicationId(const QString & value)
|
||||
{
|
||||
m_id = value;
|
||||
}
|
||||
|
||||
private: /* data */
|
||||
QString m_id;
|
||||
QString m_id;
|
||||
};
|
||||
|
||||
class LocalPeer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LocalPeer(QObject *parent, const ApplicationId &appId);
|
||||
~LocalPeer();
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout);
|
||||
ApplicationId applicationId() const;
|
||||
LocalPeer(QObject *parent, const ApplicationId &appId);
|
||||
~LocalPeer();
|
||||
bool isClient();
|
||||
bool sendMessage(const QString &message, int timeout);
|
||||
ApplicationId applicationId() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void messageReceived(const QString &message);
|
||||
void messageReceived(const QString &message);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void receiveConnection();
|
||||
void receiveConnection();
|
||||
|
||||
protected:
|
||||
ApplicationId id;
|
||||
QString socketName;
|
||||
std::unique_ptr<QLocalServer> server;
|
||||
std::unique_ptr<LockedFile> lockFile;
|
||||
ApplicationId id;
|
||||
QString socketName;
|
||||
std::unique_ptr<QLocalServer> server;
|
||||
std::unique_ptr<LockedFile> lockFile;
|
||||
};
|
||||
|
@ -67,60 +67,60 @@ static const char* ack = "ack";
|
||||
|
||||
ApplicationId ApplicationId::fromTraditionalApp()
|
||||
{
|
||||
QString protoId = QCoreApplication::applicationFilePath();
|
||||
QString protoId = QCoreApplication::applicationFilePath();
|
||||
#if defined(Q_OS_WIN)
|
||||
protoId = protoId.toLower();
|
||||
protoId = protoId.toLower();
|
||||
#endif
|
||||
auto prefix = protoId.section(QLatin1Char('/'), -1);
|
||||
prefix.remove(QRegExp("[^a-zA-Z]"));
|
||||
prefix.truncate(6);
|
||||
QByteArray idc = protoId.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
auto socketName = QLatin1String("qtsingleapp-") + prefix + QLatin1Char('-') + QString::number(idNum, 16);
|
||||
auto prefix = protoId.section(QLatin1Char('/'), -1);
|
||||
prefix.remove(QRegExp("[^a-zA-Z]"));
|
||||
prefix.truncate(6);
|
||||
QByteArray idc = protoId.toUtf8();
|
||||
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||
auto socketName = QLatin1String("qtsingleapp-") + prefix + QLatin1Char('-') + QString::number(idNum, 16);
|
||||
#if defined(Q_OS_WIN)
|
||||
if (!pProcessIdToSessionId)
|
||||
{
|
||||
QLibrary lib("kernel32");
|
||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||
}
|
||||
if (pProcessIdToSessionId)
|
||||
{
|
||||
DWORD sessionId = 0;
|
||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||
}
|
||||
if (!pProcessIdToSessionId)
|
||||
{
|
||||
QLibrary lib("kernel32");
|
||||
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||
}
|
||||
if (pProcessIdToSessionId)
|
||||
{
|
||||
DWORD sessionId = 0;
|
||||
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||
}
|
||||
#else
|
||||
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||
#endif
|
||||
return ApplicationId(socketName);
|
||||
return ApplicationId(socketName);
|
||||
}
|
||||
|
||||
ApplicationId ApplicationId::fromPathAndVersion(const QString& dataPath, const QString& version)
|
||||
{
|
||||
QCryptographicHash shasum(QCryptographicHash::Algorithm::Sha1);
|
||||
QString result = dataPath + QLatin1Char('-') + version;
|
||||
shasum.addData(result.toUtf8());
|
||||
return ApplicationId(QLatin1String("qtsingleapp-") + QString::fromLatin1(shasum.result().toHex()));
|
||||
QCryptographicHash shasum(QCryptographicHash::Algorithm::Sha1);
|
||||
QString result = dataPath + QLatin1Char('-') + version;
|
||||
shasum.addData(result.toUtf8());
|
||||
return ApplicationId(QLatin1String("qtsingleapp-") + QString::fromLatin1(shasum.result().toHex()));
|
||||
}
|
||||
|
||||
ApplicationId ApplicationId::fromCustomId(const QString& id)
|
||||
{
|
||||
return ApplicationId(QLatin1String("qtsingleapp-") + id);
|
||||
return ApplicationId(QLatin1String("qtsingleapp-") + id);
|
||||
}
|
||||
|
||||
ApplicationId ApplicationId::fromRawString(const QString& id)
|
||||
{
|
||||
return ApplicationId(id);
|
||||
return ApplicationId(id);
|
||||
}
|
||||
|
||||
LocalPeer::LocalPeer(QObject * parent, const ApplicationId &appId)
|
||||
: QObject(parent), id(appId)
|
||||
: QObject(parent), id(appId)
|
||||
{
|
||||
socketName = id.toString();
|
||||
server.reset(new QLocalServer());
|
||||
QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile");
|
||||
lockFile.reset(new LockedFile(lockName));
|
||||
lockFile->open(QIODevice::ReadWrite);
|
||||
socketName = id.toString();
|
||||
server.reset(new QLocalServer());
|
||||
QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile");
|
||||
lockFile.reset(new LockedFile(lockName));
|
||||
lockFile->open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
LocalPeer::~LocalPeer()
|
||||
@ -129,113 +129,113 @@ LocalPeer::~LocalPeer()
|
||||
|
||||
ApplicationId LocalPeer::applicationId() const
|
||||
{
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
bool LocalPeer::isClient()
|
||||
{
|
||||
if (lockFile->isLocked())
|
||||
return false;
|
||||
if (lockFile->isLocked())
|
||||
return false;
|
||||
|
||||
if (!lockFile->lock(LockedFile::WriteLock, false))
|
||||
return true;
|
||||
if (!lockFile->lock(LockedFile::WriteLock, false))
|
||||
return true;
|
||||
|
||||
bool res = server->listen(socketName);
|
||||
bool res = server->listen(socketName);
|
||||
#if defined(Q_OS_UNIX)
|
||||
// ### Workaround
|
||||
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
||||
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||
res = server->listen(socketName);
|
||||
}
|
||||
// ### Workaround
|
||||
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
||||
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||
res = server->listen(socketName);
|
||||
}
|
||||
#endif
|
||||
if (!res)
|
||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||
QObject::connect(server.get(), SIGNAL(newConnection()), SLOT(receiveConnection()));
|
||||
return false;
|
||||
if (!res)
|
||||
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||
QObject::connect(server.get(), SIGNAL(newConnection()), SLOT(receiveConnection()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LocalPeer::sendMessage(const QString &message, int timeout)
|
||||
{
|
||||
if (!isClient())
|
||||
return false;
|
||||
if (!isClient())
|
||||
return false;
|
||||
|
||||
QLocalSocket socket;
|
||||
bool connOk = false;
|
||||
for(int i = 0; i < 2; i++) {
|
||||
// Try twice, in case the other instance is just starting up
|
||||
socket.connectToServer(socketName);
|
||||
connOk = socket.waitForConnected(timeout/2);
|
||||
if (connOk || i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
}
|
||||
if (!connOk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QLocalSocket socket;
|
||||
bool connOk = false;
|
||||
for(int i = 0; i < 2; i++) {
|
||||
// Try twice, in case the other instance is just starting up
|
||||
socket.connectToServer(socketName);
|
||||
connOk = socket.waitForConnected(timeout/2);
|
||||
if (connOk || i)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
}
|
||||
if (!connOk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray uMsg(message.toUtf8());
|
||||
QDataStream ds(&socket);
|
||||
QByteArray uMsg(message.toUtf8());
|
||||
QDataStream ds(&socket);
|
||||
|
||||
ds.writeBytes(uMsg.constData(), uMsg.size());
|
||||
if(!socket.waitForBytesWritten(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ds.writeBytes(uMsg.constData(), uMsg.size());
|
||||
if(!socket.waitForBytesWritten(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// wait for 'ack'
|
||||
if(!socket.waitForReadyRead(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// wait for 'ack'
|
||||
if(!socket.waitForReadyRead(timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure we got 'ack'
|
||||
if(!(socket.read(qstrlen(ack)) == ack))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// make sure we got 'ack'
|
||||
if(!(socket.read(qstrlen(ack)) == ack))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LocalPeer::receiveConnection()
|
||||
{
|
||||
QLocalSocket* socket = server->nextPendingConnection();
|
||||
if (!socket)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QLocalSocket* socket = server->nextPendingConnection();
|
||||
if (!socket)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
||||
{
|
||||
socket->waitForReadyRead();
|
||||
}
|
||||
QDataStream ds(socket);
|
||||
QByteArray uMsg;
|
||||
quint32 remaining;
|
||||
ds >> remaining;
|
||||
uMsg.resize(remaining);
|
||||
int got = 0;
|
||||
char* uMsgBuf = uMsg.data();
|
||||
do
|
||||
{
|
||||
got = ds.readRawData(uMsgBuf, remaining);
|
||||
remaining -= got;
|
||||
uMsgBuf += got;
|
||||
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
||||
if (got < 0)
|
||||
{
|
||||
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
QString message(QString::fromUtf8(uMsg));
|
||||
socket->write(ack, qstrlen(ack));
|
||||
socket->waitForBytesWritten(1000);
|
||||
socket->waitForDisconnected(1000); // make sure client reads ack
|
||||
delete socket;
|
||||
emit messageReceived(message); //### (might take a long time to return)
|
||||
while (socket->bytesAvailable() < (int)sizeof(quint32))
|
||||
{
|
||||
socket->waitForReadyRead();
|
||||
}
|
||||
QDataStream ds(socket);
|
||||
QByteArray uMsg;
|
||||
quint32 remaining;
|
||||
ds >> remaining;
|
||||
uMsg.resize(remaining);
|
||||
int got = 0;
|
||||
char* uMsgBuf = uMsg.data();
|
||||
do
|
||||
{
|
||||
got = ds.readRawData(uMsgBuf, remaining);
|
||||
remaining -= got;
|
||||
uMsgBuf += got;
|
||||
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
||||
if (got < 0)
|
||||
{
|
||||
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
QString message(QString::fromUtf8(uMsg));
|
||||
socket->write(ack, qstrlen(ack));
|
||||
socket->waitForBytesWritten(1000);
|
||||
socket->waitForDisconnected(1000); // make sure client reads ack
|
||||
delete socket;
|
||||
emit messageReceived(message); //### (might take a long time to return)
|
||||
}
|
||||
|
@ -41,70 +41,70 @@
|
||||
#include "LockedFile.h"
|
||||
|
||||
/*!
|
||||
\class QtLockedFile
|
||||
\class QtLockedFile
|
||||
|
||||
\brief The QtLockedFile class extends QFile with advisory locking
|
||||
functions.
|
||||
\brief The QtLockedFile class extends QFile with advisory locking
|
||||
functions.
|
||||
|
||||
A file may be locked in read or write mode. Multiple instances of
|
||||
\e QtLockedFile, created in multiple processes running on the same
|
||||
machine, may have a file locked in read mode. Exactly one instance
|
||||
may have it locked in write mode. A read and a write lock cannot
|
||||
exist simultaneously on the same file.
|
||||
A file may be locked in read or write mode. Multiple instances of
|
||||
\e QtLockedFile, created in multiple processes running on the same
|
||||
machine, may have a file locked in read mode. Exactly one instance
|
||||
may have it locked in write mode. A read and a write lock cannot
|
||||
exist simultaneously on the same file.
|
||||
|
||||
The file locks are advisory. This means that nothing prevents
|
||||
another process from manipulating a locked file using QFile or
|
||||
file system functions offered by the OS. Serialization is only
|
||||
guaranteed if all processes that access the file use
|
||||
QLockedFile. Also, while holding a lock on a file, a process
|
||||
must not open the same file again (through any API), or locks
|
||||
can be unexpectedly lost.
|
||||
The file locks are advisory. This means that nothing prevents
|
||||
another process from manipulating a locked file using QFile or
|
||||
file system functions offered by the OS. Serialization is only
|
||||
guaranteed if all processes that access the file use
|
||||
QLockedFile. Also, while holding a lock on a file, a process
|
||||
must not open the same file again (through any API), or locks
|
||||
can be unexpectedly lost.
|
||||
|
||||
The lock provided by an instance of \e QtLockedFile is released
|
||||
whenever the program terminates. This is true even when the
|
||||
program crashes and no destructors are called.
|
||||
The lock provided by an instance of \e QtLockedFile is released
|
||||
whenever the program terminates. This is true even when the
|
||||
program crashes and no destructors are called.
|
||||
*/
|
||||
|
||||
/*! \enum QtLockedFile::LockMode
|
||||
|
||||
This enum describes the available lock modes.
|
||||
This enum describes the available lock modes.
|
||||
|
||||
\value ReadLock A read lock.
|
||||
\value WriteLock A write lock.
|
||||
\value NoLock Neither a read lock nor a write lock.
|
||||
\value ReadLock A read lock.
|
||||
\value WriteLock A write lock.
|
||||
\value NoLock Neither a read lock nor a write lock.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an unlocked \e QtLockedFile object. This constructor
|
||||
behaves in the same way as \e QFile::QFile().
|
||||
Constructs an unlocked \e QtLockedFile object. This constructor
|
||||
behaves in the same way as \e QFile::QFile().
|
||||
|
||||
\sa QFile::QFile()
|
||||
\sa QFile::QFile()
|
||||
*/
|
||||
LockedFile::LockedFile()
|
||||
: QFile()
|
||||
: QFile()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
#endif
|
||||
m_lock_mode = NoLock;
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||
constructor behaves in the same way as \e QFile::QFile(const
|
||||
QString&).
|
||||
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||
constructor behaves in the same way as \e QFile::QFile(const
|
||||
QString&).
|
||||
|
||||
\sa QFile::QFile()
|
||||
\sa QFile::QFile()
|
||||
*/
|
||||
LockedFile::LockedFile(const QString &name)
|
||||
: QFile(name)
|
||||
: QFile(name)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
wmutex = 0;
|
||||
rmutex = 0;
|
||||
#endif
|
||||
m_lock_mode = NoLock;
|
||||
m_lock_mode = NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -122,72 +122,72 @@ Returns true if successful; otherwise false.
|
||||
*/
|
||||
bool LockedFile::open(OpenMode mode)
|
||||
{
|
||||
if (mode & QIODevice::Truncate) {
|
||||
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||
return false;
|
||||
}
|
||||
return QFile::open(mode);
|
||||
if (mode & QIODevice::Truncate) {
|
||||
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||
return false;
|
||||
}
|
||||
return QFile::open(mode);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \e true if this object has a in read or write lock;
|
||||
otherwise returns \e false.
|
||||
Returns \e true if this object has a in read or write lock;
|
||||
otherwise returns \e false.
|
||||
|
||||
\sa lockMode()
|
||||
\sa lockMode()
|
||||
*/
|
||||
bool LockedFile::isLocked() const
|
||||
{
|
||||
return m_lock_mode != NoLock;
|
||||
return m_lock_mode != NoLock;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the type of lock currently held by this object, or \e
|
||||
QtLockedFile::NoLock.
|
||||
Returns the type of lock currently held by this object, or \e
|
||||
QtLockedFile::NoLock.
|
||||
|
||||
\sa isLocked()
|
||||
\sa isLocked()
|
||||
*/
|
||||
LockedFile::LockMode LockedFile::lockMode() const
|
||||
{
|
||||
return m_lock_mode;
|
||||
return m_lock_mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
||||
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
||||
|
||||
Obtains a lock of type \a mode. The file must be opened before it
|
||||
can be locked.
|
||||
Obtains a lock of type \a mode. The file must be opened before it
|
||||
can be locked.
|
||||
|
||||
If \a block is true, this function will block until the lock is
|
||||
aquired. If \a block is false, this function returns \e false
|
||||
immediately if the lock cannot be aquired.
|
||||
If \a block is true, this function will block until the lock is
|
||||
aquired. If \a block is false, this function returns \e false
|
||||
immediately if the lock cannot be aquired.
|
||||
|
||||
If this object already has a lock of type \a mode, this function
|
||||
returns \e true immediately. If this object has a lock of a
|
||||
different type than \a mode, the lock is first released and then a
|
||||
new lock is obtained.
|
||||
If this object already has a lock of type \a mode, this function
|
||||
returns \e true immediately. If this object has a lock of a
|
||||
different type than \a mode, the lock is first released and then a
|
||||
new lock is obtained.
|
||||
|
||||
This function returns \e true if, after it executes, the file is
|
||||
locked by this object, and \e false otherwise.
|
||||
This function returns \e true if, after it executes, the file is
|
||||
locked by this object, and \e false otherwise.
|
||||
|
||||
\sa unlock(), isLocked(), lockMode()
|
||||
\sa unlock(), isLocked(), lockMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool QtLockedFile::unlock()
|
||||
\fn bool QtLockedFile::unlock()
|
||||
|
||||
Releases a lock.
|
||||
Releases a lock.
|
||||
|
||||
If the object has no lock, this function returns immediately.
|
||||
If the object has no lock, this function returns immediately.
|
||||
|
||||
This function returns \e true if, after it executes, the file is
|
||||
not locked by this object, and \e false otherwise.
|
||||
This function returns \e true if, after it executes, the file is
|
||||
not locked by this object, and \e false otherwise.
|
||||
|
||||
\sa lock(), isLocked(), lockMode()
|
||||
\sa lock(), isLocked(), lockMode()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QtLockedFile::~QtLockedFile()
|
||||
\fn QtLockedFile::~QtLockedFile()
|
||||
|
||||
Destroys the \e QtLockedFile object. If any locks were held, they
|
||||
are released.
|
||||
Destroys the \e QtLockedFile object. If any locks were held, they
|
||||
are released.
|
||||
*/
|
||||
|
@ -48,30 +48,30 @@
|
||||
class LockedFile : public QFile
|
||||
{
|
||||
public:
|
||||
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
||||
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
||||
|
||||
LockedFile();
|
||||
LockedFile(const QString &name);
|
||||
~LockedFile();
|
||||
LockedFile();
|
||||
LockedFile(const QString &name);
|
||||
~LockedFile();
|
||||
|
||||
bool open(OpenMode mode);
|
||||
bool open(OpenMode mode);
|
||||
|
||||
bool lock(LockMode mode, bool block = true);
|
||||
bool unlock();
|
||||
bool isLocked() const;
|
||||
LockMode lockMode() const;
|
||||
bool lock(LockMode mode, bool block = true);
|
||||
bool unlock();
|
||||
bool isLocked() const;
|
||||
LockMode lockMode() const;
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
Qt::HANDLE wmutex;
|
||||
Qt::HANDLE rmutex;
|
||||
QVector<Qt::HANDLE> rmutexes;
|
||||
QString mutexname;
|
||||
Qt::HANDLE wmutex;
|
||||
Qt::HANDLE rmutex;
|
||||
QVector<Qt::HANDLE> rmutexes;
|
||||
QString mutexname;
|
||||
|
||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||
#endif
|
||||
|
||||
LockMode m_lock_mode;
|
||||
LockMode m_lock_mode;
|
||||
};
|
||||
|
@ -47,68 +47,68 @@
|
||||
|
||||
bool LockedFile::lock(LockMode mode, bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
||||
int cmd = block ? F_SETLKW : F_SETLK;
|
||||
int ret = fcntl(handle(), cmd, &fl);
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
||||
int cmd = block ? F_SETLKW : F_SETLK;
|
||||
int ret = fcntl(handle(), cmd, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (ret == -1) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool LockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isLocked())
|
||||
return true;
|
||||
if (!isLocked())
|
||||
return true;
|
||||
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = F_UNLCK;
|
||||
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||
struct flock fl;
|
||||
fl.l_whence = SEEK_SET;
|
||||
fl.l_start = 0;
|
||||
fl.l_len = 0;
|
||||
fl.l_type = F_UNLCK;
|
||||
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||
|
||||
if (ret == -1) {
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (ret == -1) {
|
||||
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lock_mode = NoLock;
|
||||
return true;
|
||||
m_lock_mode = NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
LockedFile::~LockedFile()
|
||||
{
|
||||
if (isOpen())
|
||||
unlock();
|
||||
if (isOpen())
|
||||
unlock();
|
||||
}
|
||||
|
@ -48,158 +48,158 @@
|
||||
|
||||
Qt::HANDLE LockedFile::getMutexHandle(int idx, bool doCreate)
|
||||
{
|
||||
if (mutexname.isEmpty()) {
|
||||
QFileInfo fi(*this);
|
||||
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||
+ fi.absoluteFilePath().toLower();
|
||||
}
|
||||
QString mname(mutexname);
|
||||
if (idx >= 0)
|
||||
mname += QString::number(idx);
|
||||
if (mutexname.isEmpty()) {
|
||||
QFileInfo fi(*this);
|
||||
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||
+ fi.absoluteFilePath().toLower();
|
||||
}
|
||||
QString mname(mutexname);
|
||||
if (idx >= 0)
|
||||
mname += QString::number(idx);
|
||||
|
||||
Qt::HANDLE mutex;
|
||||
if (doCreate) {
|
||||
mutex = CreateMutexW(NULL, FALSE, (LPCWSTR)mname.utf16());
|
||||
if (!mutex) {
|
||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (LPCWSTR)mname.utf16());
|
||||
if (!mutex) {
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return mutex;
|
||||
Qt::HANDLE mutex;
|
||||
if (doCreate) {
|
||||
mutex = CreateMutexW(NULL, FALSE, (LPCWSTR)mname.utf16());
|
||||
if (!mutex) {
|
||||
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (LPCWSTR)mname.utf16());
|
||||
if (!mutex) {
|
||||
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return mutex;
|
||||
}
|
||||
|
||||
bool LockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
||||
{
|
||||
Q_ASSERT(mutex);
|
||||
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||
switch (res) {
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
return true;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||
}
|
||||
return false;
|
||||
Q_ASSERT(mutex);
|
||||
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||
switch (res) {
|
||||
case WAIT_OBJECT_0:
|
||||
case WAIT_ABANDONED:
|
||||
return true;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
break;
|
||||
default:
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool LockedFile::lock(LockMode mode, bool block)
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::lock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
if (mode == NoLock)
|
||||
return unlock();
|
||||
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
if (mode == m_lock_mode)
|
||||
return true;
|
||||
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
if (m_lock_mode != NoLock)
|
||||
unlock();
|
||||
|
||||
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||
return false;
|
||||
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||
return false;
|
||||
|
||||
if (!waitMutex(wmutex, block))
|
||||
return false;
|
||||
if (!waitMutex(wmutex, block))
|
||||
return false;
|
||||
|
||||
if (mode == ReadLock) {
|
||||
int idx = 0;
|
||||
for (; idx < MAX_READERS; idx++) {
|
||||
rmutex = getMutexHandle(idx, false);
|
||||
if (!rmutex || waitMutex(rmutex, false))
|
||||
break;
|
||||
CloseHandle(rmutex);
|
||||
}
|
||||
bool ok = true;
|
||||
if (idx >= MAX_READERS) {
|
||||
qWarning("QtLockedFile::lock(): too many readers");
|
||||
rmutex = 0;
|
||||
ok = false;
|
||||
}
|
||||
else if (!rmutex) {
|
||||
rmutex = getMutexHandle(idx, true);
|
||||
if (!rmutex || !waitMutex(rmutex, false))
|
||||
ok = false;
|
||||
}
|
||||
if (!ok && rmutex) {
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
ReleaseMutex(wmutex);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(rmutexes.isEmpty());
|
||||
for (int i = 0; i < MAX_READERS; i++) {
|
||||
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||
if (mutex)
|
||||
rmutexes.append(mutex);
|
||||
}
|
||||
if (rmutexes.size()) {
|
||||
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||
TRUE, block ? INFINITE : 0);
|
||||
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||
if (res != WAIT_TIMEOUT)
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == ReadLock) {
|
||||
int idx = 0;
|
||||
for (; idx < MAX_READERS; idx++) {
|
||||
rmutex = getMutexHandle(idx, false);
|
||||
if (!rmutex || waitMutex(rmutex, false))
|
||||
break;
|
||||
CloseHandle(rmutex);
|
||||
}
|
||||
bool ok = true;
|
||||
if (idx >= MAX_READERS) {
|
||||
qWarning("QtLockedFile::lock(): too many readers");
|
||||
rmutex = 0;
|
||||
ok = false;
|
||||
}
|
||||
else if (!rmutex) {
|
||||
rmutex = getMutexHandle(idx, true);
|
||||
if (!rmutex || !waitMutex(rmutex, false))
|
||||
ok = false;
|
||||
}
|
||||
if (!ok && rmutex) {
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
ReleaseMutex(wmutex);
|
||||
if (!ok)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(rmutexes.isEmpty());
|
||||
for (int i = 0; i < MAX_READERS; i++) {
|
||||
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||
if (mutex)
|
||||
rmutexes.append(mutex);
|
||||
}
|
||||
if (rmutexes.size()) {
|
||||
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||
TRUE, block ? INFINITE : 0);
|
||||
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||
if (res != WAIT_TIMEOUT)
|
||||
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
m_lock_mode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LockedFile::unlock()
|
||||
{
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
if (!isOpen()) {
|
||||
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isLocked())
|
||||
return true;
|
||||
if (!isLocked())
|
||||
return true;
|
||||
|
||||
if (m_lock_mode == ReadLock) {
|
||||
ReleaseMutex(rmutex);
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
else {
|
||||
foreach(Qt::HANDLE mutex, rmutexes) {
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
}
|
||||
rmutexes.clear();
|
||||
ReleaseMutex(wmutex);
|
||||
}
|
||||
if (m_lock_mode == ReadLock) {
|
||||
ReleaseMutex(rmutex);
|
||||
CloseHandle(rmutex);
|
||||
rmutex = 0;
|
||||
}
|
||||
else {
|
||||
foreach(Qt::HANDLE mutex, rmutexes) {
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
}
|
||||
rmutexes.clear();
|
||||
ReleaseMutex(wmutex);
|
||||
}
|
||||
|
||||
m_lock_mode = LockedFile::NoLock;
|
||||
return true;
|
||||
m_lock_mode = LockedFile::NoLock;
|
||||
return true;
|
||||
}
|
||||
|
||||
LockedFile::~LockedFile()
|
||||
{
|
||||
if (isOpen())
|
||||
unlock();
|
||||
if (wmutex)
|
||||
CloseHandle(wmutex);
|
||||
if (isOpen())
|
||||
unlock();
|
||||
if (wmutex)
|
||||
CloseHandle(wmutex);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ set(CMAKE_AUTOMOC ON)
|
||||
include(TestBigEndian)
|
||||
test_big_endian(BIGENDIAN)
|
||||
if(${BIGENDIAN})
|
||||
add_definitions(-DMULTIMC_BIG_ENDIAN)
|
||||
add_definitions(-DMULTIMC_BIG_ENDIAN)
|
||||
endif(${BIGENDIAN})
|
||||
|
||||
# Find Qt
|
||||
|
@ -6,80 +6,80 @@ namespace java
|
||||
{
|
||||
std::string annotation::toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl;
|
||||
ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl;
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
std::pair<uint16_t, element_value *> &val = name_val_pairs[i];
|
||||
auto name_idx = val.first;
|
||||
ss << pool[name_idx].str_data << "(" << name_idx << ")"
|
||||
<< " = " << val.second->toString() << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
std::ostringstream ss;
|
||||
ss << "Annotation type : " << type_index << " - " << pool[type_index].str_data << std::endl;
|
||||
ss << "Contains " << name_val_pairs.size() << " pairs:" << std::endl;
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
std::pair<uint16_t, element_value *> &val = name_val_pairs[i];
|
||||
auto name_idx = val.first;
|
||||
ss << pool[name_idx].str_data << "(" << name_idx << ")"
|
||||
<< " = " << val.second->toString() << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
annotation *annotation::read(util::membuffer &input, constant_pool &pool)
|
||||
{
|
||||
uint16_t type_index = 0;
|
||||
input.read_be(type_index);
|
||||
annotation *ann = new annotation(type_index, pool);
|
||||
uint16_t type_index = 0;
|
||||
input.read_be(type_index);
|
||||
annotation *ann = new annotation(type_index, pool);
|
||||
|
||||
uint16_t num_pairs = 0;
|
||||
input.read_be(num_pairs);
|
||||
while (num_pairs)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
// read name index
|
||||
input.read_be(name_idx);
|
||||
auto elem = element_value::readElementValue(input, pool);
|
||||
// read value
|
||||
ann->add_pair(name_idx, elem);
|
||||
num_pairs--;
|
||||
}
|
||||
return ann;
|
||||
uint16_t num_pairs = 0;
|
||||
input.read_be(num_pairs);
|
||||
while (num_pairs)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
// read name index
|
||||
input.read_be(name_idx);
|
||||
auto elem = element_value::readElementValue(input, pool);
|
||||
// read value
|
||||
ann->add_pair(name_idx, elem);
|
||||
num_pairs--;
|
||||
}
|
||||
return ann;
|
||||
}
|
||||
|
||||
element_value *element_value::readElementValue(util::membuffer &input,
|
||||
java::constant_pool &pool)
|
||||
java::constant_pool &pool)
|
||||
{
|
||||
element_value_type type = INVALID;
|
||||
input.read(type);
|
||||
uint16_t index = 0;
|
||||
uint16_t index2 = 0;
|
||||
std::vector<element_value *> vals;
|
||||
switch (type)
|
||||
{
|
||||
case PRIMITIVE_BYTE:
|
||||
case PRIMITIVE_CHAR:
|
||||
case PRIMITIVE_DOUBLE:
|
||||
case PRIMITIVE_FLOAT:
|
||||
case PRIMITIVE_INT:
|
||||
case PRIMITIVE_LONG:
|
||||
case PRIMITIVE_SHORT:
|
||||
case PRIMITIVE_BOOLEAN:
|
||||
case STRING:
|
||||
input.read_be(index);
|
||||
return new element_value_simple(type, index, pool);
|
||||
case ENUM_CONSTANT:
|
||||
input.read_be(index);
|
||||
input.read_be(index2);
|
||||
return new element_value_enum(type, index, index2, pool);
|
||||
case CLASS: // Class
|
||||
input.read_be(index);
|
||||
return new element_value_class(type, index, pool);
|
||||
case ANNOTATION: // Annotation
|
||||
// FIXME: runtime visibility info needs to be passed from parent
|
||||
return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool);
|
||||
case ARRAY: // Array
|
||||
input.read_be(index);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
vals.push_back(element_value::readElementValue(input, pool));
|
||||
}
|
||||
return new element_value_array(ARRAY, vals, pool);
|
||||
default:
|
||||
throw new java::classfile_exception();
|
||||
}
|
||||
element_value_type type = INVALID;
|
||||
input.read(type);
|
||||
uint16_t index = 0;
|
||||
uint16_t index2 = 0;
|
||||
std::vector<element_value *> vals;
|
||||
switch (type)
|
||||
{
|
||||
case PRIMITIVE_BYTE:
|
||||
case PRIMITIVE_CHAR:
|
||||
case PRIMITIVE_DOUBLE:
|
||||
case PRIMITIVE_FLOAT:
|
||||
case PRIMITIVE_INT:
|
||||
case PRIMITIVE_LONG:
|
||||
case PRIMITIVE_SHORT:
|
||||
case PRIMITIVE_BOOLEAN:
|
||||
case STRING:
|
||||
input.read_be(index);
|
||||
return new element_value_simple(type, index, pool);
|
||||
case ENUM_CONSTANT:
|
||||
input.read_be(index);
|
||||
input.read_be(index2);
|
||||
return new element_value_enum(type, index, index2, pool);
|
||||
case CLASS: // Class
|
||||
input.read_be(index);
|
||||
return new element_value_class(type, index, pool);
|
||||
case ANNOTATION: // Annotation
|
||||
// FIXME: runtime visibility info needs to be passed from parent
|
||||
return new element_value_annotation(ANNOTATION, annotation::read(input, pool), pool);
|
||||
case ARRAY: // Array
|
||||
input.read_be(index);
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
vals.push_back(element_value::readElementValue(input, pool));
|
||||
}
|
||||
return new element_value_array(ARRAY, vals, pool);
|
||||
default:
|
||||
throw new java::classfile_exception();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,21 +7,21 @@ namespace java
|
||||
{
|
||||
enum element_value_type : uint8_t
|
||||
{
|
||||
INVALID = 0,
|
||||
STRING = 's',
|
||||
ENUM_CONSTANT = 'e',
|
||||
CLASS = 'c',
|
||||
ANNOTATION = '@',
|
||||
ARRAY = '[', // one array dimension
|
||||
PRIMITIVE_INT = 'I', // integer
|
||||
PRIMITIVE_BYTE = 'B', // signed byte
|
||||
PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane,
|
||||
// encoded with UTF-16
|
||||
PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value
|
||||
PRIMITIVE_FLOAT = 'F', // single-precision floating-point value
|
||||
PRIMITIVE_LONG = 'J', // long integer
|
||||
PRIMITIVE_SHORT = 'S', // signed short
|
||||
PRIMITIVE_BOOLEAN = 'Z' // true or false
|
||||
INVALID = 0,
|
||||
STRING = 's',
|
||||
ENUM_CONSTANT = 'e',
|
||||
CLASS = 'c',
|
||||
ANNOTATION = '@',
|
||||
ARRAY = '[', // one array dimension
|
||||
PRIMITIVE_INT = 'I', // integer
|
||||
PRIMITIVE_BYTE = 'B', // signed byte
|
||||
PRIMITIVE_CHAR = 'C', // Unicode character code point in the Basic Multilingual Plane,
|
||||
// encoded with UTF-16
|
||||
PRIMITIVE_DOUBLE = 'D', // double-precision floating-point value
|
||||
PRIMITIVE_FLOAT = 'F', // single-precision floating-point value
|
||||
PRIMITIVE_LONG = 'J', // long integer
|
||||
PRIMITIVE_SHORT = 'S', // signed short
|
||||
PRIMITIVE_BOOLEAN = 'Z' // true or false
|
||||
};
|
||||
/**
|
||||
* The element_value structure is a discriminated union representing the value of an
|
||||
@ -37,21 +37,21 @@ enum element_value_type : uint8_t
|
||||
class element_value
|
||||
{
|
||||
protected:
|
||||
element_value_type type;
|
||||
constant_pool &pool;
|
||||
element_value_type type;
|
||||
constant_pool &pool;
|
||||
|
||||
public:
|
||||
element_value(element_value_type type, constant_pool &pool) : type(type), pool(pool) {};
|
||||
virtual ~element_value() {}
|
||||
element_value(element_value_type type, constant_pool &pool) : type(type), pool(pool) {};
|
||||
virtual ~element_value() {}
|
||||
|
||||
element_value_type getElementValueType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
element_value_type getElementValueType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual std::string toString() = 0;
|
||||
virtual std::string toString() = 0;
|
||||
|
||||
static element_value *readElementValue(util::membuffer &input, constant_pool &pool);
|
||||
static element_value *readElementValue(util::membuffer &input, constant_pool &pool);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -62,58 +62,58 @@ public:
|
||||
class annotation
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::pair<uint16_t, element_value *>> value_list;
|
||||
typedef std::vector<std::pair<uint16_t, element_value *>> value_list;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a field descriptor representing the annotation type corresponding
|
||||
* to the annotation represented by this annotation structure.
|
||||
*/
|
||||
uint16_t type_index;
|
||||
/**
|
||||
* map between element_name_index and value.
|
||||
*
|
||||
* The value of the element_name_index item must be a valid index into the constant_pool
|
||||
*table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
*representing
|
||||
* a valid field descriptor (§4.3.2) that denotes the name of the annotation type element
|
||||
*represented
|
||||
* by this element_value_pairs entry.
|
||||
*/
|
||||
value_list name_val_pairs;
|
||||
/**
|
||||
* Reference to the parent constant pool
|
||||
*/
|
||||
constant_pool &pool;
|
||||
/**
|
||||
* The value of the type_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a field descriptor representing the annotation type corresponding
|
||||
* to the annotation represented by this annotation structure.
|
||||
*/
|
||||
uint16_t type_index;
|
||||
/**
|
||||
* map between element_name_index and value.
|
||||
*
|
||||
* The value of the element_name_index item must be a valid index into the constant_pool
|
||||
*table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
*representing
|
||||
* a valid field descriptor (§4.3.2) that denotes the name of the annotation type element
|
||||
*represented
|
||||
* by this element_value_pairs entry.
|
||||
*/
|
||||
value_list name_val_pairs;
|
||||
/**
|
||||
* Reference to the parent constant pool
|
||||
*/
|
||||
constant_pool &pool;
|
||||
|
||||
public:
|
||||
annotation(uint16_t type_index, constant_pool &pool)
|
||||
: type_index(type_index), pool(pool) {};
|
||||
~annotation()
|
||||
{
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
delete name_val_pairs[i].second;
|
||||
}
|
||||
}
|
||||
void add_pair(uint16_t key, element_value *value)
|
||||
{
|
||||
name_val_pairs.push_back(std::make_pair(key, value));
|
||||
}
|
||||
;
|
||||
value_list::const_iterator begin()
|
||||
{
|
||||
return name_val_pairs.cbegin();
|
||||
}
|
||||
value_list::const_iterator end()
|
||||
{
|
||||
return name_val_pairs.cend();
|
||||
}
|
||||
std::string toString();
|
||||
static annotation *read(util::membuffer &input, constant_pool &pool);
|
||||
annotation(uint16_t type_index, constant_pool &pool)
|
||||
: type_index(type_index), pool(pool) {};
|
||||
~annotation()
|
||||
{
|
||||
for (unsigned i = 0; i < name_val_pairs.size(); i++)
|
||||
{
|
||||
delete name_val_pairs[i].second;
|
||||
}
|
||||
}
|
||||
void add_pair(uint16_t key, element_value *value)
|
||||
{
|
||||
name_val_pairs.push_back(std::make_pair(key, value));
|
||||
}
|
||||
;
|
||||
value_list::const_iterator begin()
|
||||
{
|
||||
return name_val_pairs.cbegin();
|
||||
}
|
||||
value_list::const_iterator end()
|
||||
{
|
||||
return name_val_pairs.cend();
|
||||
}
|
||||
std::string toString();
|
||||
static annotation *read(util::membuffer &input, constant_pool &pool);
|
||||
};
|
||||
typedef std::vector<annotation *> annotation_table;
|
||||
|
||||
@ -121,158 +121,158 @@ typedef std::vector<annotation *> annotation_table;
|
||||
class element_value_simple : public element_value
|
||||
{
|
||||
protected:
|
||||
/// index of the constant in the constant pool
|
||||
uint16_t index;
|
||||
/// index of the constant in the constant pool
|
||||
uint16_t index;
|
||||
|
||||
public:
|
||||
element_value_simple(element_value_type type, uint16_t index, constant_pool &pool)
|
||||
: element_value(type, pool), index(index) {
|
||||
// TODO: verify consistency
|
||||
};
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return pool[index].toString();
|
||||
}
|
||||
;
|
||||
element_value_simple(element_value_type type, uint16_t index, constant_pool &pool)
|
||||
: element_value(type, pool), index(index) {
|
||||
// TODO: verify consistency
|
||||
};
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return pool[index].toString();
|
||||
}
|
||||
;
|
||||
};
|
||||
/// The enum_const_value item is used if the tag item is 'e'.
|
||||
class element_value_enum : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The value of the type_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a valid field descriptor (§4.3.2) that denotes the internal form of the
|
||||
* binary
|
||||
* name (§4.2.1) of the type of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t typeIndex;
|
||||
/**
|
||||
* The value of the const_name_index item must be a valid index into the constant_pool
|
||||
* table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the simple name of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t valueIndex;
|
||||
/**
|
||||
* The value of the type_name_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing a valid field descriptor (§4.3.2) that denotes the internal form of the
|
||||
* binary
|
||||
* name (§4.2.1) of the type of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t typeIndex;
|
||||
/**
|
||||
* The value of the const_name_index item must be a valid index into the constant_pool
|
||||
* table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the simple name of the enum constant represented by this element_value
|
||||
* structure.
|
||||
*/
|
||||
uint16_t valueIndex;
|
||||
|
||||
public:
|
||||
element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getValueIndex()
|
||||
{
|
||||
return valueIndex;
|
||||
}
|
||||
uint16_t getTypeIndex()
|
||||
{
|
||||
return typeIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "enum value";
|
||||
}
|
||||
;
|
||||
element_value_enum(element_value_type type, uint16_t typeIndex, uint16_t valueIndex,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), typeIndex(typeIndex), valueIndex(valueIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getValueIndex()
|
||||
{
|
||||
return valueIndex;
|
||||
}
|
||||
uint16_t getTypeIndex()
|
||||
{
|
||||
return typeIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "enum value";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
class element_value_class : public element_value
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The class_info_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the return descriptor (§4.3.3) of the type that is reified by the class
|
||||
* represented by this element_value structure.
|
||||
*
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
*
|
||||
* Or in plain english, you can store type information in annotations. Yay.
|
||||
*/
|
||||
uint16_t classIndex;
|
||||
/**
|
||||
* The class_info_index item must be a valid index into the constant_pool table.
|
||||
* The constant_pool entry at that index must be a CONSTANT_Utf8_info (§4.4.7) structure
|
||||
* representing the return descriptor (§4.3.3) of the type that is reified by the class
|
||||
* represented by this element_value structure.
|
||||
*
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
*
|
||||
* Or in plain english, you can store type information in annotations. Yay.
|
||||
*/
|
||||
uint16_t classIndex;
|
||||
|
||||
public:
|
||||
element_value_class(element_value_type type, uint16_t classIndex, constant_pool &pool)
|
||||
: element_value(type, pool), classIndex(classIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return classIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "class";
|
||||
}
|
||||
;
|
||||
element_value_class(element_value_type type, uint16_t classIndex, constant_pool &pool)
|
||||
: element_value(type, pool), classIndex(classIndex)
|
||||
{
|
||||
// TODO: verify consistency
|
||||
}
|
||||
uint16_t getIndex()
|
||||
{
|
||||
return classIndex;
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "class";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
/// nested annotations... yay
|
||||
class element_value_annotation : public element_value
|
||||
{
|
||||
private:
|
||||
annotation *nestedAnnotation;
|
||||
annotation *nestedAnnotation;
|
||||
|
||||
public:
|
||||
element_value_annotation(element_value_type type, annotation *nestedAnnotation,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), nestedAnnotation(nestedAnnotation) {};
|
||||
~element_value_annotation()
|
||||
{
|
||||
if (nestedAnnotation)
|
||||
{
|
||||
delete nestedAnnotation;
|
||||
nestedAnnotation = nullptr;
|
||||
}
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "nested annotation";
|
||||
}
|
||||
;
|
||||
element_value_annotation(element_value_type type, annotation *nestedAnnotation,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), nestedAnnotation(nestedAnnotation) {};
|
||||
~element_value_annotation()
|
||||
{
|
||||
if (nestedAnnotation)
|
||||
{
|
||||
delete nestedAnnotation;
|
||||
nestedAnnotation = nullptr;
|
||||
}
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "nested annotation";
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
/// and arrays!
|
||||
class element_value_array : public element_value
|
||||
{
|
||||
public:
|
||||
typedef std::vector<element_value *> elem_vec;
|
||||
typedef std::vector<element_value *> elem_vec;
|
||||
|
||||
protected:
|
||||
elem_vec values;
|
||||
elem_vec values;
|
||||
|
||||
public:
|
||||
element_value_array(element_value_type type, std::vector<element_value *> &values,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), values(values) {};
|
||||
~element_value_array()
|
||||
{
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
{
|
||||
delete values[i];
|
||||
}
|
||||
}
|
||||
;
|
||||
elem_vec::const_iterator begin()
|
||||
{
|
||||
return values.cbegin();
|
||||
}
|
||||
elem_vec::const_iterator end()
|
||||
{
|
||||
return values.cend();
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
;
|
||||
element_value_array(element_value_type type, std::vector<element_value *> &values,
|
||||
constant_pool &pool)
|
||||
: element_value(type, pool), values(values) {};
|
||||
~element_value_array()
|
||||
{
|
||||
for (unsigned i = 0; i < values.size(); i++)
|
||||
{
|
||||
delete values[i];
|
||||
}
|
||||
}
|
||||
;
|
||||
elem_vec::const_iterator begin()
|
||||
{
|
||||
return values.cbegin();
|
||||
}
|
||||
elem_vec::const_iterator end()
|
||||
{
|
||||
return values.cend();
|
||||
}
|
||||
virtual std::string toString()
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
;
|
||||
};
|
||||
}
|
@ -11,146 +11,146 @@ namespace java
|
||||
class classfile : public util::membuffer
|
||||
{
|
||||
public:
|
||||
classfile(char *data, std::size_t size) : membuffer(data, size)
|
||||
{
|
||||
valid = false;
|
||||
is_synthetic = false;
|
||||
read_be(magic);
|
||||
if (magic != 0xCAFEBABE)
|
||||
throw new classfile_exception();
|
||||
read_be(minor_version);
|
||||
read_be(major_version);
|
||||
constants.load(*this);
|
||||
read_be(access_flags);
|
||||
read_be(this_class);
|
||||
read_be(super_class);
|
||||
classfile(char *data, std::size_t size) : membuffer(data, size)
|
||||
{
|
||||
valid = false;
|
||||
is_synthetic = false;
|
||||
read_be(magic);
|
||||
if (magic != 0xCAFEBABE)
|
||||
throw new classfile_exception();
|
||||
read_be(minor_version);
|
||||
read_be(major_version);
|
||||
constants.load(*this);
|
||||
read_be(access_flags);
|
||||
read_be(this_class);
|
||||
read_be(super_class);
|
||||
|
||||
// Interfaces
|
||||
uint16_t iface_count = 0;
|
||||
read_be(iface_count);
|
||||
while (iface_count)
|
||||
{
|
||||
uint16_t iface;
|
||||
read_be(iface);
|
||||
interfaces.push_back(iface);
|
||||
iface_count--;
|
||||
}
|
||||
// Interfaces
|
||||
uint16_t iface_count = 0;
|
||||
read_be(iface_count);
|
||||
while (iface_count)
|
||||
{
|
||||
uint16_t iface;
|
||||
read_be(iface);
|
||||
interfaces.push_back(iface);
|
||||
iface_count--;
|
||||
}
|
||||
|
||||
// Fields
|
||||
// read fields (and attributes from inside fields) (and possible inner classes. yay for
|
||||
// recursion!)
|
||||
// for now though, we will ignore all attributes
|
||||
/*
|
||||
* field_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t field_count = 0;
|
||||
read_be(field_count);
|
||||
while (field_count)
|
||||
{
|
||||
// skip field stuff
|
||||
skip(6);
|
||||
// and skip field attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
field_count--;
|
||||
}
|
||||
// Fields
|
||||
// read fields (and attributes from inside fields) (and possible inner classes. yay for
|
||||
// recursion!)
|
||||
// for now though, we will ignore all attributes
|
||||
/*
|
||||
* field_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t field_count = 0;
|
||||
read_be(field_count);
|
||||
while (field_count)
|
||||
{
|
||||
// skip field stuff
|
||||
skip(6);
|
||||
// and skip field attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
field_count--;
|
||||
}
|
||||
|
||||
// class methods
|
||||
/*
|
||||
* method_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t method_count = 0;
|
||||
read_be(method_count);
|
||||
while (method_count)
|
||||
{
|
||||
skip(6);
|
||||
// and skip method attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
method_count--;
|
||||
}
|
||||
// class methods
|
||||
/*
|
||||
* method_info
|
||||
* {
|
||||
* u2 access_flags;
|
||||
* u2 name_index;
|
||||
* u2 descriptor_index;
|
||||
* u2 attributes_count;
|
||||
* attribute_info attributes[attributes_count];
|
||||
* }
|
||||
*/
|
||||
uint16_t method_count = 0;
|
||||
read_be(method_count);
|
||||
while (method_count)
|
||||
{
|
||||
skip(6);
|
||||
// and skip method attributes
|
||||
uint16_t attr_count = 0;
|
||||
read_be(attr_count);
|
||||
while (attr_count)
|
||||
{
|
||||
skip(2);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
skip(attr_length);
|
||||
attr_count--;
|
||||
}
|
||||
method_count--;
|
||||
}
|
||||
|
||||
// class attributes
|
||||
// there are many kinds of attributes. this is just the generic wrapper structure.
|
||||
// type is decided by attribute name. extensions to the standard are *possible*
|
||||
// class annotations are one kind of a attribute (one per class)
|
||||
/*
|
||||
* attribute_info
|
||||
* {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u1 info[attribute_length];
|
||||
* }
|
||||
*/
|
||||
uint16_t class_attr_count = 0;
|
||||
read_be(class_attr_count);
|
||||
while (class_attr_count)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
read_be(name_idx);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
// class attributes
|
||||
// there are many kinds of attributes. this is just the generic wrapper structure.
|
||||
// type is decided by attribute name. extensions to the standard are *possible*
|
||||
// class annotations are one kind of a attribute (one per class)
|
||||
/*
|
||||
* attribute_info
|
||||
* {
|
||||
* u2 attribute_name_index;
|
||||
* u4 attribute_length;
|
||||
* u1 info[attribute_length];
|
||||
* }
|
||||
*/
|
||||
uint16_t class_attr_count = 0;
|
||||
read_be(class_attr_count);
|
||||
while (class_attr_count)
|
||||
{
|
||||
uint16_t name_idx = 0;
|
||||
read_be(name_idx);
|
||||
uint32_t attr_length = 0;
|
||||
read_be(attr_length);
|
||||
|
||||
auto name = constants[name_idx];
|
||||
if (name.str_data == "RuntimeVisibleAnnotations")
|
||||
{
|
||||
uint16_t num_annotations = 0;
|
||||
read_be(num_annotations);
|
||||
while (num_annotations)
|
||||
{
|
||||
visible_class_annotations.push_back(annotation::read(*this, constants));
|
||||
num_annotations--;
|
||||
}
|
||||
}
|
||||
else
|
||||
skip(attr_length);
|
||||
class_attr_count--;
|
||||
}
|
||||
valid = true;
|
||||
}
|
||||
;
|
||||
bool valid;
|
||||
bool is_synthetic;
|
||||
uint32_t magic;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
constant_pool constants;
|
||||
uint16_t access_flags;
|
||||
uint16_t this_class;
|
||||
uint16_t super_class;
|
||||
// interfaces this class implements ? must be. investigate.
|
||||
std::vector<uint16_t> interfaces;
|
||||
// FIXME: doesn't free up memory on delete
|
||||
java::annotation_table visible_class_annotations;
|
||||
auto name = constants[name_idx];
|
||||
if (name.str_data == "RuntimeVisibleAnnotations")
|
||||
{
|
||||
uint16_t num_annotations = 0;
|
||||
read_be(num_annotations);
|
||||
while (num_annotations)
|
||||
{
|
||||
visible_class_annotations.push_back(annotation::read(*this, constants));
|
||||
num_annotations--;
|
||||
}
|
||||
}
|
||||
else
|
||||
skip(attr_length);
|
||||
class_attr_count--;
|
||||
}
|
||||
valid = true;
|
||||
}
|
||||
;
|
||||
bool valid;
|
||||
bool is_synthetic;
|
||||
uint32_t magic;
|
||||
uint16_t minor_version;
|
||||
uint16_t major_version;
|
||||
constant_pool constants;
|
||||
uint16_t access_flags;
|
||||
uint16_t this_class;
|
||||
uint16_t super_class;
|
||||
// interfaces this class implements ? must be. investigate.
|
||||
std::vector<uint16_t> interfaces;
|
||||
// FIXME: doesn't free up memory on delete
|
||||
java::annotation_table visible_class_annotations;
|
||||
};
|
||||
}
|
@ -26,58 +26,58 @@ namespace classparser
|
||||
|
||||
QString GetMinecraftJarVersion(QString jarName)
|
||||
{
|
||||
QString version;
|
||||
QString version;
|
||||
|
||||
// check if minecraft.jar exists
|
||||
QFile jar(jarName);
|
||||
if (!jar.exists())
|
||||
return version;
|
||||
// check if minecraft.jar exists
|
||||
QFile jar(jarName);
|
||||
if (!jar.exists())
|
||||
return version;
|
||||
|
||||
// open minecraft.jar
|
||||
QuaZip zip(&jar);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
return version;
|
||||
// open minecraft.jar
|
||||
QuaZip zip(&jar);
|
||||
if (!zip.open(QuaZip::mdUnzip))
|
||||
return version;
|
||||
|
||||
// open Minecraft.class
|
||||
zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive);
|
||||
QuaZipFile Minecraft(&zip);
|
||||
if (!Minecraft.open(QuaZipFile::ReadOnly))
|
||||
return version;
|
||||
// open Minecraft.class
|
||||
zip.setCurrentFile("net/minecraft/client/Minecraft.class", QuaZip::csSensitive);
|
||||
QuaZipFile Minecraft(&zip);
|
||||
if (!Minecraft.open(QuaZipFile::ReadOnly))
|
||||
return version;
|
||||
|
||||
// read Minecraft.class
|
||||
qint64 size = Minecraft.size();
|
||||
char *classfile = new char[size];
|
||||
Minecraft.read(classfile, size);
|
||||
// read Minecraft.class
|
||||
qint64 size = Minecraft.size();
|
||||
char *classfile = new char[size];
|
||||
Minecraft.read(classfile, size);
|
||||
|
||||
// parse Minecraft.class
|
||||
try
|
||||
{
|
||||
char *temp = classfile;
|
||||
java::classfile MinecraftClass(temp, size);
|
||||
java::constant_pool constants = MinecraftClass.constants;
|
||||
for (java::constant_pool::container_type::const_iterator iter = constants.begin();
|
||||
iter != constants.end(); iter++)
|
||||
{
|
||||
const java::constant &constant = *iter;
|
||||
if (constant.type != java::constant_type_t::j_string_data)
|
||||
continue;
|
||||
const std::string &str = constant.str_data;
|
||||
qDebug() << QString::fromStdString(str);
|
||||
if (str.compare(0, 20, "Minecraft Minecraft ") == 0)
|
||||
{
|
||||
version = str.substr(20).data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const java::classfile_exception &) { }
|
||||
// parse Minecraft.class
|
||||
try
|
||||
{
|
||||
char *temp = classfile;
|
||||
java::classfile MinecraftClass(temp, size);
|
||||
java::constant_pool constants = MinecraftClass.constants;
|
||||
for (java::constant_pool::container_type::const_iterator iter = constants.begin();
|
||||
iter != constants.end(); iter++)
|
||||
{
|
||||
const java::constant &constant = *iter;
|
||||
if (constant.type != java::constant_type_t::j_string_data)
|
||||
continue;
|
||||
const std::string &str = constant.str_data;
|
||||
qDebug() << QString::fromStdString(str);
|
||||
if (str.compare(0, 20, "Minecraft Minecraft ") == 0)
|
||||
{
|
||||
version = str.substr(20).data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const java::classfile_exception &) { }
|
||||
|
||||
// clean up
|
||||
delete[] classfile;
|
||||
Minecraft.close();
|
||||
zip.close();
|
||||
jar.close();
|
||||
// clean up
|
||||
delete[] classfile;
|
||||
Minecraft.close();
|
||||
zip.close();
|
||||
jar.close();
|
||||
|
||||
return version;
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
@ -6,159 +6,159 @@ namespace java
|
||||
{
|
||||
enum class constant_type_t : uint8_t
|
||||
{
|
||||
j_hole = 0, // HACK: this is a hole in the array, because java is crazy
|
||||
j_string_data = 1,
|
||||
j_int = 3,
|
||||
j_float = 4,
|
||||
j_long = 5,
|
||||
j_double = 6,
|
||||
j_class = 7,
|
||||
j_string = 8,
|
||||
j_fieldref = 9,
|
||||
j_methodref = 10,
|
||||
j_interface_methodref = 11,
|
||||
j_nameandtype = 12
|
||||
// FIXME: missing some constant types, see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
|
||||
j_hole = 0, // HACK: this is a hole in the array, because java is crazy
|
||||
j_string_data = 1,
|
||||
j_int = 3,
|
||||
j_float = 4,
|
||||
j_long = 5,
|
||||
j_double = 6,
|
||||
j_class = 7,
|
||||
j_string = 8,
|
||||
j_fieldref = 9,
|
||||
j_methodref = 10,
|
||||
j_interface_methodref = 11,
|
||||
j_nameandtype = 12
|
||||
// FIXME: missing some constant types, see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4
|
||||
};
|
||||
|
||||
struct ref_type_t
|
||||
{
|
||||
/**
|
||||
* Class reference:
|
||||
* an index within the constant pool to a UTF-8 string containing
|
||||
* the fully qualified class name (in internal format)
|
||||
* Used for j_class, j_fieldref, j_methodref and j_interface_methodref
|
||||
*/
|
||||
uint16_t class_idx;
|
||||
// used for j_fieldref, j_methodref and j_interface_methodref
|
||||
uint16_t name_and_type_idx;
|
||||
/**
|
||||
* Class reference:
|
||||
* an index within the constant pool to a UTF-8 string containing
|
||||
* the fully qualified class name (in internal format)
|
||||
* Used for j_class, j_fieldref, j_methodref and j_interface_methodref
|
||||
*/
|
||||
uint16_t class_idx;
|
||||
// used for j_fieldref, j_methodref and j_interface_methodref
|
||||
uint16_t name_and_type_idx;
|
||||
};
|
||||
|
||||
struct name_and_type_t
|
||||
{
|
||||
uint16_t name_index;
|
||||
uint16_t descriptor_index;
|
||||
uint16_t name_index;
|
||||
uint16_t descriptor_index;
|
||||
};
|
||||
|
||||
class constant
|
||||
{
|
||||
public:
|
||||
constant_type_t type = constant_type_t::j_hole;
|
||||
constant_type_t type = constant_type_t::j_hole;
|
||||
|
||||
constant(util::membuffer &buf)
|
||||
{
|
||||
buf.read(type);
|
||||
constant(util::membuffer &buf)
|
||||
{
|
||||
buf.read(type);
|
||||
|
||||
// load data depending on type
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_float:
|
||||
buf.read_be(data.int_data);
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
buf.read_be(data.int_data); // same as float data really
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
buf.read_be(data.long_data);
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
buf.read_be(data.long_data); // same as double
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
case constant_type_t::j_methodref:
|
||||
case constant_type_t::j_interface_methodref:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
buf.read_be(data.ref_type.name_and_type_idx);
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
buf.read_be(data.index);
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
// HACK HACK: for now, we call these UTF-8 and do no further processing.
|
||||
// Later, we should do some decoding. It's really modified UTF-8
|
||||
// * U+0000 is represented as 0xC0,0x80 invalid character
|
||||
// * any single zero byte ends the string
|
||||
// * characters above U+10000 are encoded like in CESU-8
|
||||
buf.read_jstr(str_data);
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
buf.read_be(data.name_and_type.name_index);
|
||||
buf.read_be(data.name_and_type.descriptor_index);
|
||||
break;
|
||||
default:
|
||||
// invalid constant type!
|
||||
throw new classfile_exception();
|
||||
}
|
||||
}
|
||||
constant(int)
|
||||
{
|
||||
}
|
||||
// load data depending on type
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_float:
|
||||
buf.read_be(data.int_data);
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
buf.read_be(data.int_data); // same as float data really
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
buf.read_be(data.long_data);
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
buf.read_be(data.long_data); // same as double
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
case constant_type_t::j_methodref:
|
||||
case constant_type_t::j_interface_methodref:
|
||||
buf.read_be(data.ref_type.class_idx);
|
||||
buf.read_be(data.ref_type.name_and_type_idx);
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
buf.read_be(data.index);
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
// HACK HACK: for now, we call these UTF-8 and do no further processing.
|
||||
// Later, we should do some decoding. It's really modified UTF-8
|
||||
// * U+0000 is represented as 0xC0,0x80 invalid character
|
||||
// * any single zero byte ends the string
|
||||
// * characters above U+10000 are encoded like in CESU-8
|
||||
buf.read_jstr(str_data);
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
buf.read_be(data.name_and_type.name_index);
|
||||
buf.read_be(data.name_and_type.descriptor_index);
|
||||
break;
|
||||
default:
|
||||
// invalid constant type!
|
||||
throw new classfile_exception();
|
||||
}
|
||||
}
|
||||
constant(int)
|
||||
{
|
||||
}
|
||||
|
||||
std::string toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_hole:
|
||||
ss << "Fake legacy entry";
|
||||
break;
|
||||
case constant_type_t::j_float:
|
||||
ss << "Float: " << data.float_data;
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
ss << "Double: " << data.double_data;
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
ss << "Int: " << data.int_data;
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
ss << "Long: " << data.long_data;
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
ss << "StrData: " << str_data;
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
ss << "Str: " << data.index;
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
ss << "FieldRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_methodref:
|
||||
ss << "MethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_interface_methodref:
|
||||
ss << "IfMethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
ss << "Class: " << data.ref_type.class_idx;
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
ss << "NameAndType: " << data.name_and_type.name_index << " "
|
||||
<< data.name_and_type.descriptor_index;
|
||||
break;
|
||||
default:
|
||||
ss << "Invalid entry (" << int(type) << ")";
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
std::string toString()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
switch (type)
|
||||
{
|
||||
case constant_type_t::j_hole:
|
||||
ss << "Fake legacy entry";
|
||||
break;
|
||||
case constant_type_t::j_float:
|
||||
ss << "Float: " << data.float_data;
|
||||
break;
|
||||
case constant_type_t::j_double:
|
||||
ss << "Double: " << data.double_data;
|
||||
break;
|
||||
case constant_type_t::j_int:
|
||||
ss << "Int: " << data.int_data;
|
||||
break;
|
||||
case constant_type_t::j_long:
|
||||
ss << "Long: " << data.long_data;
|
||||
break;
|
||||
case constant_type_t::j_string_data:
|
||||
ss << "StrData: " << str_data;
|
||||
break;
|
||||
case constant_type_t::j_string:
|
||||
ss << "Str: " << data.index;
|
||||
break;
|
||||
case constant_type_t::j_fieldref:
|
||||
ss << "FieldRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_methodref:
|
||||
ss << "MethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_interface_methodref:
|
||||
ss << "IfMethodRef: " << data.ref_type.class_idx << " " << data.ref_type.name_and_type_idx;
|
||||
break;
|
||||
case constant_type_t::j_class:
|
||||
ss << "Class: " << data.ref_type.class_idx;
|
||||
break;
|
||||
case constant_type_t::j_nameandtype:
|
||||
ss << "NameAndType: " << data.name_and_type.name_index << " "
|
||||
<< data.name_and_type.descriptor_index;
|
||||
break;
|
||||
default:
|
||||
ss << "Invalid entry (" << int(type) << ")";
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string str_data; /** String data in 'modified utf-8'.*/
|
||||
std::string str_data; /** String data in 'modified utf-8'.*/
|
||||
|
||||
// store everything here.
|
||||
union
|
||||
{
|
||||
int32_t int_data;
|
||||
int64_t long_data;
|
||||
float float_data;
|
||||
double double_data;
|
||||
uint16_t index;
|
||||
ref_type_t ref_type;
|
||||
name_and_type_t name_and_type;
|
||||
} data = {0};
|
||||
// store everything here.
|
||||
union
|
||||
{
|
||||
int32_t int_data;
|
||||
int64_t long_data;
|
||||
float float_data;
|
||||
double double_data;
|
||||
uint16_t index;
|
||||
ref_type_t ref_type;
|
||||
name_and_type_t name_and_type;
|
||||
} data = {0};
|
||||
};
|
||||
|
||||
/**
|
||||
@ -168,64 +168,64 @@ public:
|
||||
class constant_pool
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a pool of constants
|
||||
*/
|
||||
constant_pool()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Load a java constant pool
|
||||
*/
|
||||
void load(util::membuffer &buf)
|
||||
{
|
||||
// FIXME: @SANITY this should check for the end of buffer.
|
||||
uint16_t length = 0;
|
||||
buf.read_be(length);
|
||||
length--;
|
||||
const constant *last_constant = nullptr;
|
||||
while (length)
|
||||
{
|
||||
const constant &cnst = constant(buf);
|
||||
constants.push_back(cnst);
|
||||
last_constant = &constants[constants.size() - 1];
|
||||
if (last_constant->type == constant_type_t::j_double ||
|
||||
last_constant->type == constant_type_t::j_long)
|
||||
{
|
||||
// push in a fake constant to preserve indexing
|
||||
constants.push_back(constant(0));
|
||||
length -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef std::vector<java::constant> container_type;
|
||||
/**
|
||||
* Access constants based on jar file index numbers (index of the first element is 1)
|
||||
*/
|
||||
java::constant &operator[](std::size_t constant_index)
|
||||
{
|
||||
if (constant_index == 0 || constant_index > constants.size())
|
||||
{
|
||||
throw new classfile_exception();
|
||||
}
|
||||
return constants[constant_index - 1];
|
||||
}
|
||||
;
|
||||
container_type::const_iterator begin() const
|
||||
{
|
||||
return constants.begin();
|
||||
}
|
||||
;
|
||||
container_type::const_iterator end() const
|
||||
{
|
||||
return constants.end();
|
||||
}
|
||||
/**
|
||||
* Create a pool of constants
|
||||
*/
|
||||
constant_pool()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Load a java constant pool
|
||||
*/
|
||||
void load(util::membuffer &buf)
|
||||
{
|
||||
// FIXME: @SANITY this should check for the end of buffer.
|
||||
uint16_t length = 0;
|
||||
buf.read_be(length);
|
||||
length--;
|
||||
const constant *last_constant = nullptr;
|
||||
while (length)
|
||||
{
|
||||
const constant &cnst = constant(buf);
|
||||
constants.push_back(cnst);
|
||||
last_constant = &constants[constants.size() - 1];
|
||||
if (last_constant->type == constant_type_t::j_double ||
|
||||
last_constant->type == constant_type_t::j_long)
|
||||
{
|
||||
// push in a fake constant to preserve indexing
|
||||
constants.push_back(constant(0));
|
||||
length -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
typedef std::vector<java::constant> container_type;
|
||||
/**
|
||||
* Access constants based on jar file index numbers (index of the first element is 1)
|
||||
*/
|
||||
java::constant &operator[](std::size_t constant_index)
|
||||
{
|
||||
if (constant_index == 0 || constant_index > constants.size())
|
||||
{
|
||||
throw new classfile_exception();
|
||||
}
|
||||
return constants[constant_index - 1];
|
||||
}
|
||||
;
|
||||
container_type::const_iterator begin() const
|
||||
{
|
||||
return constants.begin();
|
||||
}
|
||||
;
|
||||
container_type::const_iterator end() const
|
||||
{
|
||||
return constants.end();
|
||||
}
|
||||
|
||||
private:
|
||||
container_type constants;
|
||||
container_type constants;
|
||||
};
|
||||
}
|
||||
|
@ -9,67 +9,67 @@ namespace util
|
||||
#ifdef MULTIMC_BIG_ENDIAN
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
;
|
||||
#else
|
||||
inline uint64_t bigswap(uint64_t x)
|
||||
{
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
}
|
||||
|
||||
inline uint32_t bigswap(uint32_t x)
|
||||
{
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
}
|
||||
|
||||
inline uint16_t bigswap(uint16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
inline int64_t bigswap(int64_t x)
|
||||
{
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
return (x >> 56) | ((x << 40) & 0x00FF000000000000) | ((x << 24) & 0x0000FF0000000000) |
|
||||
((x << 8) & 0x000000FF00000000) | ((x >> 8) & 0x00000000FF000000) |
|
||||
((x >> 24) & 0x0000000000FF0000) | ((x >> 40) & 0x000000000000FF00) | (x << 56);
|
||||
}
|
||||
|
||||
inline int32_t bigswap(int32_t x)
|
||||
{
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
return (x >> 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x << 24);
|
||||
}
|
||||
|
||||
inline int16_t bigswap(int16_t x)
|
||||
{
|
||||
return (x >> 8) | (x << 8);
|
||||
return (x >> 8) | (x << 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -10,54 +10,54 @@ namespace util
|
||||
class membuffer
|
||||
{
|
||||
public:
|
||||
membuffer(char *buffer, std::size_t size)
|
||||
{
|
||||
current = start = buffer;
|
||||
end = start + size;
|
||||
}
|
||||
~membuffer()
|
||||
{
|
||||
// maybe? possibly? left out to avoid confusion. for now.
|
||||
// delete start;
|
||||
}
|
||||
/**
|
||||
* Read some value. That's all ;)
|
||||
*/
|
||||
template <class T> void read(T &val)
|
||||
{
|
||||
val = *(T *)current;
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a big-endian number
|
||||
* valid for 2-byte, 4-byte and 8-byte variables
|
||||
*/
|
||||
template <class T> void read_be(T &val)
|
||||
{
|
||||
val = util::bigswap(*(T *)current);
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a string in the format:
|
||||
* 2B length (big endian, unsigned)
|
||||
* length bytes data
|
||||
*/
|
||||
void read_jstr(std::string &str)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
read_be(length);
|
||||
str.append(current, length);
|
||||
current += length;
|
||||
}
|
||||
/**
|
||||
* Skip N bytes
|
||||
*/
|
||||
void skip(std::size_t N)
|
||||
{
|
||||
current += N;
|
||||
}
|
||||
membuffer(char *buffer, std::size_t size)
|
||||
{
|
||||
current = start = buffer;
|
||||
end = start + size;
|
||||
}
|
||||
~membuffer()
|
||||
{
|
||||
// maybe? possibly? left out to avoid confusion. for now.
|
||||
// delete start;
|
||||
}
|
||||
/**
|
||||
* Read some value. That's all ;)
|
||||
*/
|
||||
template <class T> void read(T &val)
|
||||
{
|
||||
val = *(T *)current;
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a big-endian number
|
||||
* valid for 2-byte, 4-byte and 8-byte variables
|
||||
*/
|
||||
template <class T> void read_be(T &val)
|
||||
{
|
||||
val = util::bigswap(*(T *)current);
|
||||
current += sizeof(T);
|
||||
}
|
||||
/**
|
||||
* Read a string in the format:
|
||||
* 2B length (big endian, unsigned)
|
||||
* length bytes data
|
||||
*/
|
||||
void read_jstr(std::string &str)
|
||||
{
|
||||
uint16_t length = 0;
|
||||
read_be(length);
|
||||
str.append(current, length);
|
||||
current += length;
|
||||
}
|
||||
/**
|
||||
* Skip N bytes
|
||||
*/
|
||||
void skip(std::size_t N)
|
||||
{
|
||||
current += N;
|
||||
}
|
||||
|
||||
private:
|
||||
char *start, *end, *current;
|
||||
char *start, *end, *current;
|
||||
};
|
||||
}
|
||||
|
@ -8,59 +8,59 @@ class GAnalyticsWorker;
|
||||
|
||||
class GAnalytics : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(LogLevel)
|
||||
Q_OBJECT
|
||||
Q_ENUMS(LogLevel)
|
||||
|
||||
public:
|
||||
explicit GAnalytics(const QString &trackingID, const QString &clientID, const int version, QObject *parent = 0);
|
||||
~GAnalytics();
|
||||
explicit GAnalytics(const QString &trackingID, const QString &clientID, const int version, QObject *parent = 0);
|
||||
~GAnalytics();
|
||||
|
||||
public:
|
||||
enum LogLevel
|
||||
{
|
||||
Debug,
|
||||
Info,
|
||||
Error
|
||||
};
|
||||
enum LogLevel
|
||||
{
|
||||
Debug,
|
||||
Info,
|
||||
Error
|
||||
};
|
||||
|
||||
int version();
|
||||
int version();
|
||||
|
||||
void setLogLevel(LogLevel logLevel);
|
||||
LogLevel logLevel() const;
|
||||
void setLogLevel(LogLevel logLevel);
|
||||
LogLevel logLevel() const;
|
||||
|
||||
// Getter and Setters
|
||||
void setViewportSize(const QString &viewportSize);
|
||||
QString viewportSize() const;
|
||||
// Getter and Setters
|
||||
void setViewportSize(const QString &viewportSize);
|
||||
QString viewportSize() const;
|
||||
|
||||
void setLanguage(const QString &language);
|
||||
QString language() const;
|
||||
void setLanguage(const QString &language);
|
||||
QString language() const;
|
||||
|
||||
void setAnonymizeIPs(bool anonymize);
|
||||
bool anonymizeIPs();
|
||||
void setAnonymizeIPs(bool anonymize);
|
||||
bool anonymizeIPs();
|
||||
|
||||
void setSendInterval(int milliseconds);
|
||||
int sendInterval() const;
|
||||
void setSendInterval(int milliseconds);
|
||||
int sendInterval() const;
|
||||
|
||||
void enable(bool state = true);
|
||||
bool isEnabled();
|
||||
void enable(bool state = true);
|
||||
bool isEnabled();
|
||||
|
||||
/// Get or set the network access manager. If none is set, the class creates its own on the first request
|
||||
void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager);
|
||||
QNetworkAccessManager *networkAccessManager() const;
|
||||
/// Get or set the network access manager. If none is set, the class creates its own on the first request
|
||||
void setNetworkAccessManager(QNetworkAccessManager *networkAccessManager);
|
||||
QNetworkAccessManager *networkAccessManager() const;
|
||||
|
||||
public slots:
|
||||
void sendScreenView(const QString &screenName, const QVariantMap &customValues = QVariantMap());
|
||||
void sendEvent(const QString &category, const QString &action, const QString &label = QString(), const QVariant &value = QVariant(),
|
||||
const QVariantMap &customValues = QVariantMap());
|
||||
void sendException(const QString &exceptionDescription, bool exceptionFatal = true, const QVariantMap &customValues = QVariantMap());
|
||||
void startSession();
|
||||
void endSession();
|
||||
void sendScreenView(const QString &screenName, const QVariantMap &customValues = QVariantMap());
|
||||
void sendEvent(const QString &category, const QString &action, const QString &label = QString(), const QVariant &value = QVariant(),
|
||||
const QVariantMap &customValues = QVariantMap());
|
||||
void sendException(const QString &exceptionDescription, bool exceptionFatal = true, const QVariantMap &customValues = QVariantMap());
|
||||
void startSession();
|
||||
void endSession();
|
||||
|
||||
private:
|
||||
GAnalyticsWorker *d;
|
||||
GAnalyticsWorker *d;
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &outStream, const GAnalytics &analytics);
|
||||
friend QDataStream &operator>>(QDataStream &inStream, GAnalytics &analytics);
|
||||
friend QDataStream &operator<<(QDataStream &outStream, const GAnalytics &analytics);
|
||||
friend QDataStream &operator>>(QDataStream &inStream, GAnalytics &analytics);
|
||||
};
|
||||
|
||||
QDataStream &operator<<(QDataStream &outStream, const GAnalytics &analytics);
|
||||
|
@ -16,10 +16,10 @@
|
||||
|
||||
GAnalytics::GAnalytics(const QString &trackingID, const QString &clientID, const int version, QObject *parent) : QObject(parent)
|
||||
{
|
||||
d = new GAnalyticsWorker(this);
|
||||
d->m_trackingID = trackingID;
|
||||
d->m_clientID = clientID;
|
||||
d->m_version = version;
|
||||
d = new GAnalyticsWorker(this);
|
||||
d->m_trackingID = trackingID;
|
||||
d->m_clientID = clientID;
|
||||
d->m_version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -27,100 +27,100 @@ GAnalytics::GAnalytics(const QString &trackingID, const QString &clientID, const
|
||||
*/
|
||||
GAnalytics::~GAnalytics()
|
||||
{
|
||||
delete d;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void GAnalytics::setLogLevel(GAnalytics::LogLevel logLevel)
|
||||
{
|
||||
d->m_logLevel = logLevel;
|
||||
d->m_logLevel = logLevel;
|
||||
}
|
||||
|
||||
GAnalytics::LogLevel GAnalytics::logLevel() const
|
||||
{
|
||||
return d->m_logLevel;
|
||||
return d->m_logLevel;
|
||||
}
|
||||
|
||||
// SETTER and GETTER
|
||||
void GAnalytics::setViewportSize(const QString &viewportSize)
|
||||
{
|
||||
d->m_viewportSize = viewportSize;
|
||||
d->m_viewportSize = viewportSize;
|
||||
}
|
||||
|
||||
QString GAnalytics::viewportSize() const
|
||||
{
|
||||
return d->m_viewportSize;
|
||||
return d->m_viewportSize;
|
||||
}
|
||||
|
||||
void GAnalytics::setLanguage(const QString &language)
|
||||
{
|
||||
d->m_language = language;
|
||||
d->m_language = language;
|
||||
}
|
||||
|
||||
QString GAnalytics::language() const
|
||||
{
|
||||
return d->m_language;
|
||||
return d->m_language;
|
||||
}
|
||||
|
||||
void GAnalytics::setAnonymizeIPs(bool anonymize)
|
||||
{
|
||||
d->m_anonymizeIPs = anonymize;
|
||||
d->m_anonymizeIPs = anonymize;
|
||||
}
|
||||
|
||||
bool GAnalytics::anonymizeIPs()
|
||||
{
|
||||
return d->m_anonymizeIPs;
|
||||
return d->m_anonymizeIPs;
|
||||
}
|
||||
|
||||
void GAnalytics::setSendInterval(int milliseconds)
|
||||
{
|
||||
d->m_timer.setInterval(milliseconds);
|
||||
d->m_timer.setInterval(milliseconds);
|
||||
}
|
||||
|
||||
int GAnalytics::sendInterval() const
|
||||
{
|
||||
return (d->m_timer.interval());
|
||||
return (d->m_timer.interval());
|
||||
}
|
||||
|
||||
bool GAnalytics::isEnabled()
|
||||
{
|
||||
return d->m_isEnabled;
|
||||
return d->m_isEnabled;
|
||||
}
|
||||
|
||||
void GAnalytics::enable(bool state)
|
||||
{
|
||||
d->enable(state);
|
||||
d->enable(state);
|
||||
}
|
||||
|
||||
int GAnalytics::version()
|
||||
{
|
||||
return d->m_version;
|
||||
return d->m_version;
|
||||
}
|
||||
|
||||
void GAnalytics::setNetworkAccessManager(QNetworkAccessManager *networkAccessManager)
|
||||
{
|
||||
if (d->networkManager != networkAccessManager)
|
||||
{
|
||||
// Delete the old network manager if it was our child
|
||||
if (d->networkManager && d->networkManager->parent() == this)
|
||||
{
|
||||
d->networkManager->deleteLater();
|
||||
}
|
||||
if (d->networkManager != networkAccessManager)
|
||||
{
|
||||
// Delete the old network manager if it was our child
|
||||
if (d->networkManager && d->networkManager->parent() == this)
|
||||
{
|
||||
d->networkManager->deleteLater();
|
||||
}
|
||||
|
||||
d->networkManager = networkAccessManager;
|
||||
}
|
||||
d->networkManager = networkAccessManager;
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkAccessManager *GAnalytics::networkAccessManager() const
|
||||
{
|
||||
return d->networkManager;
|
||||
return d->networkManager;
|
||||
}
|
||||
|
||||
static void appendCustomValues(QUrlQuery &query, const QVariantMap &customValues)
|
||||
{
|
||||
for (QVariantMap::const_iterator iter = customValues.begin(); iter != customValues.end(); ++iter)
|
||||
{
|
||||
query.addQueryItem(iter.key(), iter.value().toString());
|
||||
}
|
||||
for (QVariantMap::const_iterator iter = customValues.begin(); iter != customValues.end(); ++iter)
|
||||
{
|
||||
query.addQueryItem(iter.key(), iter.value().toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,15 +131,15 @@ static void appendCustomValues(QUrlQuery &query, const QVariantMap &customValues
|
||||
*/
|
||||
void GAnalytics::sendScreenView(const QString &screenName, const QVariantMap &customValues)
|
||||
{
|
||||
d->logMessage(Info, QString("ScreenView: %1").arg(screenName));
|
||||
d->logMessage(Info, QString("ScreenView: %1").arg(screenName));
|
||||
|
||||
QUrlQuery query = d->buildStandardPostQuery("screenview");
|
||||
query.addQueryItem("cd", screenName);
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
appendCustomValues(query, customValues);
|
||||
QUrlQuery query = d->buildStandardPostQuery("screenview");
|
||||
query.addQueryItem("cd", screenName);
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
appendCustomValues(query, customValues);
|
||||
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,19 +149,19 @@ void GAnalytics::sendScreenView(const QString &screenName, const QVariantMap &cu
|
||||
*/
|
||||
void GAnalytics::sendEvent(const QString &category, const QString &action, const QString &label, const QVariant &value, const QVariantMap &customValues)
|
||||
{
|
||||
QUrlQuery query = d->buildStandardPostQuery("event");
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
query.addQueryItem("ec", category);
|
||||
query.addQueryItem("ea", action);
|
||||
if (!label.isEmpty())
|
||||
query.addQueryItem("el", label);
|
||||
if (value.isValid())
|
||||
query.addQueryItem("ev", value.toString());
|
||||
QUrlQuery query = d->buildStandardPostQuery("event");
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
query.addQueryItem("ec", category);
|
||||
query.addQueryItem("ea", action);
|
||||
if (!label.isEmpty())
|
||||
query.addQueryItem("el", label);
|
||||
if (value.isValid())
|
||||
query.addQueryItem("ev", value.toString());
|
||||
|
||||
appendCustomValues(query, customValues);
|
||||
appendCustomValues(query, customValues);
|
||||
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,23 +171,23 @@ void GAnalytics::sendEvent(const QString &category, const QString &action, const
|
||||
*/
|
||||
void GAnalytics::sendException(const QString &exceptionDescription, bool exceptionFatal, const QVariantMap &customValues)
|
||||
{
|
||||
QUrlQuery query = d->buildStandardPostQuery("exception");
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
QUrlQuery query = d->buildStandardPostQuery("exception");
|
||||
query.addQueryItem("an", d->m_appName);
|
||||
query.addQueryItem("av", d->m_appVersion);
|
||||
|
||||
query.addQueryItem("exd", exceptionDescription);
|
||||
query.addQueryItem("exd", exceptionDescription);
|
||||
|
||||
if (exceptionFatal)
|
||||
{
|
||||
query.addQueryItem("exf", "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
query.addQueryItem("exf", "0");
|
||||
}
|
||||
appendCustomValues(query, customValues);
|
||||
if (exceptionFatal)
|
||||
{
|
||||
query.addQueryItem("exf", "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
query.addQueryItem("exf", "0");
|
||||
}
|
||||
appendCustomValues(query, customValues);
|
||||
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
d->enqueQueryWithCurrentTime(query);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,9 +197,9 @@ void GAnalytics::sendException(const QString &exceptionDescription, bool excepti
|
||||
*/
|
||||
void GAnalytics::startSession()
|
||||
{
|
||||
QVariantMap customValues;
|
||||
customValues.insert("sc", "start");
|
||||
sendEvent("Session", "Start", QString(), QVariant(), customValues);
|
||||
QVariantMap customValues;
|
||||
customValues.insert("sc", "start");
|
||||
sendEvent("Session", "Start", QString(), QVariant(), customValues);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,9 +209,9 @@ void GAnalytics::startSession()
|
||||
*/
|
||||
void GAnalytics::endSession()
|
||||
{
|
||||
QVariantMap customValues;
|
||||
customValues.insert("sc", "end");
|
||||
sendEvent("Session", "End", QString(), QVariant(), customValues);
|
||||
QVariantMap customValues;
|
||||
customValues.insert("sc", "end");
|
||||
sendEvent("Session", "End", QString(), QVariant(), customValues);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,9 +219,9 @@ void GAnalytics::endSession()
|
||||
*/
|
||||
QDataStream &operator<<(QDataStream &outStream, const GAnalytics &analytics)
|
||||
{
|
||||
outStream << analytics.d->persistMessageQueue();
|
||||
outStream << analytics.d->persistMessageQueue();
|
||||
|
||||
return outStream;
|
||||
return outStream;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,9 +229,9 @@ QDataStream &operator<<(QDataStream &outStream, const GAnalytics &analytics)
|
||||
*/
|
||||
QDataStream &operator>>(QDataStream &inStream, GAnalytics &analytics)
|
||||
{
|
||||
QList<QString> dataList;
|
||||
inStream >> dataList;
|
||||
analytics.d->readMessagesFromFile(dataList);
|
||||
QList<QString> dataList;
|
||||
inStream >> dataList;
|
||||
analytics.d->readMessagesFromFile(dataList);
|
||||
|
||||
return inStream;
|
||||
return inStream;
|
||||
}
|
||||
|
@ -12,50 +12,50 @@
|
||||
const QLatin1String GAnalyticsWorker::dateTimeFormat("yyyy,MM,dd-hh:mm::ss:zzz");
|
||||
|
||||
GAnalyticsWorker::GAnalyticsWorker(GAnalytics *parent)
|
||||
: QObject(parent), q(parent), m_logLevel(GAnalytics::Error)
|
||||
: QObject(parent), q(parent), m_logLevel(GAnalytics::Error)
|
||||
{
|
||||
m_appName = QCoreApplication::instance()->applicationName();
|
||||
m_appVersion = QCoreApplication::instance()->applicationVersion();
|
||||
m_request.setUrl(QUrl("https://www.google-analytics.com/collect"));
|
||||
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
m_request.setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
|
||||
m_appName = QCoreApplication::instance()->applicationName();
|
||||
m_appVersion = QCoreApplication::instance()->applicationVersion();
|
||||
m_request.setUrl(QUrl("https://www.google-analytics.com/collect"));
|
||||
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
m_request.setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
|
||||
|
||||
m_language = QLocale::system().name().toLower().replace("_", "-");
|
||||
m_screenResolution = getScreenResolution();
|
||||
m_language = QLocale::system().name().toLower().replace("_", "-");
|
||||
m_screenResolution = getScreenResolution();
|
||||
|
||||
m_timer.setInterval(m_timerInterval);
|
||||
connect(&m_timer, &QTimer::timeout, this, &GAnalyticsWorker::postMessage);
|
||||
m_timer.setInterval(m_timerInterval);
|
||||
connect(&m_timer, &QTimer::timeout, this, &GAnalyticsWorker::postMessage);
|
||||
}
|
||||
|
||||
void GAnalyticsWorker::enable(bool state)
|
||||
{
|
||||
// state change to the same is not valid.
|
||||
if(m_isEnabled == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// state change to the same is not valid.
|
||||
if(m_isEnabled == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_isEnabled = state;
|
||||
if(m_isEnabled)
|
||||
{
|
||||
// enable -> start doing things :)
|
||||
m_timer.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// disable -> stop the timer
|
||||
m_timer.stop();
|
||||
}
|
||||
m_isEnabled = state;
|
||||
if(m_isEnabled)
|
||||
{
|
||||
// enable -> start doing things :)
|
||||
m_timer.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// disable -> stop the timer
|
||||
m_timer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void GAnalyticsWorker::logMessage(GAnalytics::LogLevel level, const QString &message)
|
||||
{
|
||||
if (m_logLevel > level)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_logLevel > level)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[Analytics]" << message;
|
||||
qDebug() << "[Analytics]" << message;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,23 +66,23 @@ void GAnalyticsWorker::logMessage(GAnalytics::LogLevel level, const QString &mes
|
||||
*/
|
||||
QUrlQuery GAnalyticsWorker::buildStandardPostQuery(const QString &type)
|
||||
{
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("v", "1");
|
||||
query.addQueryItem("tid", m_trackingID);
|
||||
query.addQueryItem("cid", m_clientID);
|
||||
if (!m_userID.isEmpty())
|
||||
{
|
||||
query.addQueryItem("uid", m_userID);
|
||||
}
|
||||
query.addQueryItem("t", type);
|
||||
query.addQueryItem("ul", m_language);
|
||||
query.addQueryItem("vp", m_viewportSize);
|
||||
query.addQueryItem("sr", m_screenResolution);
|
||||
if(m_anonymizeIPs)
|
||||
{
|
||||
query.addQueryItem("aip", "1");
|
||||
}
|
||||
return query;
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("v", "1");
|
||||
query.addQueryItem("tid", m_trackingID);
|
||||
query.addQueryItem("cid", m_clientID);
|
||||
if (!m_userID.isEmpty())
|
||||
{
|
||||
query.addQueryItem("uid", m_userID);
|
||||
}
|
||||
query.addQueryItem("t", type);
|
||||
query.addQueryItem("ul", m_language);
|
||||
query.addQueryItem("vp", m_viewportSize);
|
||||
query.addQueryItem("sr", m_screenResolution);
|
||||
if(m_anonymizeIPs)
|
||||
{
|
||||
query.addQueryItem("aip", "1");
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,10 +91,10 @@ QUrlQuery GAnalyticsWorker::buildStandardPostQuery(const QString &type)
|
||||
*/
|
||||
QString GAnalyticsWorker::getScreenResolution()
|
||||
{
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
QSize size = screen->size();
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
QSize size = screen->size();
|
||||
|
||||
return QString("%1x%2").arg(size.width()).arg(size.height());
|
||||
return QString("%1x%2").arg(size.width()).arg(size.height());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,7 +106,7 @@ QString GAnalyticsWorker::getScreenResolution()
|
||||
*/
|
||||
QString GAnalyticsWorker::getUserAgent()
|
||||
{
|
||||
return QString("%1/%2").arg(m_appName).arg(m_appVersion);
|
||||
return QString("%1/%2").arg(m_appName).arg(m_appVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,13 +118,13 @@ QString GAnalyticsWorker::getUserAgent()
|
||||
*/
|
||||
QList<QString> GAnalyticsWorker::persistMessageQueue()
|
||||
{
|
||||
QList<QString> dataList;
|
||||
foreach (QueryBuffer buffer, m_messageQueue)
|
||||
{
|
||||
dataList << buffer.postQuery.toString();
|
||||
dataList << buffer.time.toString(dateTimeFormat);
|
||||
}
|
||||
return dataList;
|
||||
QList<QString> dataList;
|
||||
foreach (QueryBuffer buffer, m_messageQueue)
|
||||
{
|
||||
dataList << buffer.postQuery.toString();
|
||||
dataList << buffer.time.toString(dateTimeFormat);
|
||||
}
|
||||
return dataList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,19 +134,19 @@ QList<QString> GAnalyticsWorker::persistMessageQueue()
|
||||
*/
|
||||
void GAnalyticsWorker::readMessagesFromFile(const QList<QString> &dataList)
|
||||
{
|
||||
QListIterator<QString> iter(dataList);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
QString queryString = iter.next();
|
||||
QString dateString = iter.next();
|
||||
QUrlQuery query;
|
||||
query.setQuery(queryString);
|
||||
QDateTime dateTime = QDateTime::fromString(dateString, dateTimeFormat);
|
||||
QueryBuffer buffer;
|
||||
buffer.postQuery = query;
|
||||
buffer.time = dateTime;
|
||||
m_messageQueue.enqueue(buffer);
|
||||
}
|
||||
QListIterator<QString> iter(dataList);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
QString queryString = iter.next();
|
||||
QString dateString = iter.next();
|
||||
QUrlQuery query;
|
||||
query.setQuery(queryString);
|
||||
QDateTime dateTime = QDateTime::fromString(dateString, dateTimeFormat);
|
||||
QueryBuffer buffer;
|
||||
buffer.postQuery = query;
|
||||
buffer.time = dateTime;
|
||||
m_messageQueue.enqueue(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,11 +156,11 @@ void GAnalyticsWorker::readMessagesFromFile(const QList<QString> &dataList)
|
||||
*/
|
||||
void GAnalyticsWorker::enqueQueryWithCurrentTime(const QUrlQuery &query)
|
||||
{
|
||||
QueryBuffer buffer;
|
||||
buffer.postQuery = query;
|
||||
buffer.time = QDateTime::currentDateTime();
|
||||
QueryBuffer buffer;
|
||||
buffer.postQuery = query;
|
||||
buffer.time = QDateTime::currentDateTime();
|
||||
|
||||
m_messageQueue.enqueue(buffer);
|
||||
m_messageQueue.enqueue(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,50 +175,50 @@ void GAnalyticsWorker::enqueQueryWithCurrentTime(const QUrlQuery &query)
|
||||
*/
|
||||
void GAnalyticsWorker::postMessage()
|
||||
{
|
||||
if (m_messageQueue.isEmpty())
|
||||
{
|
||||
// queue empty -> try sending later
|
||||
m_timer.start();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// queue has messages -> stop timer and start sending
|
||||
m_timer.stop();
|
||||
}
|
||||
if (m_messageQueue.isEmpty())
|
||||
{
|
||||
// queue empty -> try sending later
|
||||
m_timer.start();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// queue has messages -> stop timer and start sending
|
||||
m_timer.stop();
|
||||
}
|
||||
|
||||
QString connection = "close";
|
||||
if (m_messageQueue.count() > 1)
|
||||
{
|
||||
connection = "keep-alive";
|
||||
}
|
||||
QString connection = "close";
|
||||
if (m_messageQueue.count() > 1)
|
||||
{
|
||||
connection = "keep-alive";
|
||||
}
|
||||
|
||||
QueryBuffer buffer = m_messageQueue.head();
|
||||
QDateTime sendTime = QDateTime::currentDateTime();
|
||||
qint64 timeDiff = buffer.time.msecsTo(sendTime);
|
||||
QueryBuffer buffer = m_messageQueue.head();
|
||||
QDateTime sendTime = QDateTime::currentDateTime();
|
||||
qint64 timeDiff = buffer.time.msecsTo(sendTime);
|
||||
|
||||
if (timeDiff > fourHours)
|
||||
{
|
||||
// too old.
|
||||
m_messageQueue.dequeue();
|
||||
emit postMessage();
|
||||
return;
|
||||
}
|
||||
if (timeDiff > fourHours)
|
||||
{
|
||||
// too old.
|
||||
m_messageQueue.dequeue();
|
||||
emit postMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.postQuery.addQueryItem("qt", QString::number(timeDiff));
|
||||
m_request.setRawHeader("Connection", connection.toUtf8());
|
||||
m_request.setHeader(QNetworkRequest::ContentLengthHeader, buffer.postQuery.toString().length());
|
||||
buffer.postQuery.addQueryItem("qt", QString::number(timeDiff));
|
||||
m_request.setRawHeader("Connection", connection.toUtf8());
|
||||
m_request.setHeader(QNetworkRequest::ContentLengthHeader, buffer.postQuery.toString().length());
|
||||
|
||||
logMessage(GAnalytics::Debug, "Query string = " + buffer.postQuery.toString());
|
||||
logMessage(GAnalytics::Debug, "Query string = " + buffer.postQuery.toString());
|
||||
|
||||
// Create a new network access manager if we don't have one yet
|
||||
if (networkManager == NULL)
|
||||
{
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
// Create a new network access manager if we don't have one yet
|
||||
if (networkManager == NULL)
|
||||
{
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
QNetworkReply *reply = networkManager->post(m_request, buffer.postQuery.query(QUrl::EncodeUnicode).toUtf8());
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(postMessageFinished()));
|
||||
QNetworkReply *reply = networkManager->post(m_request, buffer.postQuery.query(QUrl::EncodeUnicode).toUtf8());
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(postMessageFinished()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,23 +232,23 @@ void GAnalyticsWorker::postMessage()
|
||||
*/
|
||||
void GAnalyticsWorker::postMessageFinished()
|
||||
{
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
||||
|
||||
int httpStausCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (httpStausCode < 200 || httpStausCode > 299)
|
||||
{
|
||||
logMessage(GAnalytics::Error, QString("Error posting message: %s").arg(reply->errorString()));
|
||||
int httpStausCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (httpStausCode < 200 || httpStausCode > 299)
|
||||
{
|
||||
logMessage(GAnalytics::Error, QString("Error posting message: %s").arg(reply->errorString()));
|
||||
|
||||
// An error ocurred. Try sending later.
|
||||
m_timer.start();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage(GAnalytics::Debug, "Message sent");
|
||||
}
|
||||
// An error ocurred. Try sending later.
|
||||
m_timer.start();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage(GAnalytics::Debug, "Message sent");
|
||||
}
|
||||
|
||||
m_messageQueue.dequeue();
|
||||
postMessage();
|
||||
reply->deleteLater();
|
||||
m_messageQueue.dequeue();
|
||||
postMessage();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
@ -8,58 +8,58 @@
|
||||
|
||||
struct QueryBuffer
|
||||
{
|
||||
QUrlQuery postQuery;
|
||||
QDateTime time;
|
||||
QUrlQuery postQuery;
|
||||
QDateTime time;
|
||||
};
|
||||
|
||||
class GAnalyticsWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GAnalyticsWorker(GAnalytics *parent = 0);
|
||||
explicit GAnalyticsWorker(GAnalytics *parent = 0);
|
||||
|
||||
GAnalytics *q;
|
||||
GAnalytics *q;
|
||||
|
||||
QNetworkAccessManager *networkManager = nullptr;
|
||||
QNetworkAccessManager *networkManager = nullptr;
|
||||
|
||||
QQueue<QueryBuffer> m_messageQueue;
|
||||
QTimer m_timer;
|
||||
QNetworkRequest m_request;
|
||||
GAnalytics::LogLevel m_logLevel;
|
||||
QQueue<QueryBuffer> m_messageQueue;
|
||||
QTimer m_timer;
|
||||
QNetworkRequest m_request;
|
||||
GAnalytics::LogLevel m_logLevel;
|
||||
|
||||
QString m_trackingID;
|
||||
QString m_clientID;
|
||||
QString m_userID;
|
||||
QString m_appName;
|
||||
QString m_appVersion;
|
||||
QString m_language;
|
||||
QString m_screenResolution;
|
||||
QString m_viewportSize;
|
||||
QString m_trackingID;
|
||||
QString m_clientID;
|
||||
QString m_userID;
|
||||
QString m_appName;
|
||||
QString m_appVersion;
|
||||
QString m_language;
|
||||
QString m_screenResolution;
|
||||
QString m_viewportSize;
|
||||
|
||||
bool m_anonymizeIPs = false;
|
||||
bool m_isEnabled = false;
|
||||
int m_timerInterval = 30000;
|
||||
int m_version = 0;
|
||||
bool m_anonymizeIPs = false;
|
||||
bool m_isEnabled = false;
|
||||
int m_timerInterval = 30000;
|
||||
int m_version = 0;
|
||||
|
||||
const static int fourHours = 4 * 60 * 60 * 1000;
|
||||
const static QLatin1String dateTimeFormat;
|
||||
const static int fourHours = 4 * 60 * 60 * 1000;
|
||||
const static QLatin1String dateTimeFormat;
|
||||
|
||||
public:
|
||||
void logMessage(GAnalytics::LogLevel level, const QString &message);
|
||||
void logMessage(GAnalytics::LogLevel level, const QString &message);
|
||||
|
||||
QUrlQuery buildStandardPostQuery(const QString &type);
|
||||
QString getScreenResolution();
|
||||
QString getUserAgent();
|
||||
QList<QString> persistMessageQueue();
|
||||
void readMessagesFromFile(const QList<QString> &dataList);
|
||||
QUrlQuery buildStandardPostQuery(const QString &type);
|
||||
QString getScreenResolution();
|
||||
QString getUserAgent();
|
||||
QList<QString> persistMessageQueue();
|
||||
void readMessagesFromFile(const QList<QString> &dataList);
|
||||
|
||||
void enqueQueryWithCurrentTime(const QUrlQuery &query);
|
||||
void setIsSending(bool doSend);
|
||||
void enable(bool state);
|
||||
void enqueQueryWithCurrentTime(const QUrlQuery &query);
|
||||
void setIsSending(bool doSend);
|
||||
void enable(bool state);
|
||||
|
||||
public slots:
|
||||
void postMessage();
|
||||
void postMessageFinished();
|
||||
void postMessage();
|
||||
void postMessageFinished();
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,7 @@ extern "C" {
|
||||
*************/
|
||||
|
||||
typedef enum hoedown_autolink_flags {
|
||||
HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0)
|
||||
HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0)
|
||||
} hoedown_autolink_flags;
|
||||
|
||||
|
||||
@ -28,15 +28,15 @@ int hoedown_autolink_is_safe(const uint8_t *data, size_t size);
|
||||
|
||||
/* hoedown_autolink__www: search for the next www link in data */
|
||||
size_t hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link,
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
|
||||
/* hoedown_autolink__email: search for the next email in data */
|
||||
size_t hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link,
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
|
||||
/* hoedown_autolink__url: search for the next URL in data */
|
||||
size_t hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link,
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -28,14 +28,14 @@ typedef void *(*hoedown_realloc_callback)(void *, size_t);
|
||||
typedef void (*hoedown_free_callback)(void *);
|
||||
|
||||
struct hoedown_buffer {
|
||||
uint8_t *data; /* actual character data */
|
||||
size_t size; /* size of the string */
|
||||
size_t asize; /* allocated size (0 = volatile buffer) */
|
||||
size_t unit; /* reallocation unit size (0 = read-only buffer) */
|
||||
uint8_t *data; /* actual character data */
|
||||
size_t size; /* size of the string */
|
||||
size_t asize; /* allocated size (0 = volatile buffer) */
|
||||
size_t unit; /* reallocation unit size (0 = read-only buffer) */
|
||||
|
||||
hoedown_realloc_callback data_realloc;
|
||||
hoedown_free_callback data_free;
|
||||
hoedown_free_callback buffer_free;
|
||||
hoedown_realloc_callback data_realloc;
|
||||
hoedown_free_callback data_free;
|
||||
hoedown_free_callback buffer_free;
|
||||
};
|
||||
|
||||
typedef struct hoedown_buffer hoedown_buffer;
|
||||
@ -52,11 +52,11 @@ void *hoedown_realloc(void *ptr, size_t size) __attribute__ ((malloc));
|
||||
|
||||
/* hoedown_buffer_init: initialize a buffer with custom allocators */
|
||||
void hoedown_buffer_init(
|
||||
hoedown_buffer *buffer,
|
||||
size_t unit,
|
||||
hoedown_realloc_callback data_realloc,
|
||||
hoedown_free_callback data_free,
|
||||
hoedown_free_callback buffer_free
|
||||
hoedown_buffer *buffer,
|
||||
size_t unit,
|
||||
hoedown_realloc_callback data_realloc,
|
||||
hoedown_free_callback data_free,
|
||||
hoedown_free_callback buffer_free
|
||||
);
|
||||
|
||||
/* hoedown_buffer_uninit: uninitialize an existing buffer */
|
||||
@ -116,15 +116,15 @@ void hoedown_buffer_free(hoedown_buffer *buf);
|
||||
|
||||
/* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */
|
||||
#define HOEDOWN_BUFPUTSL(output, literal) \
|
||||
hoedown_buffer_put(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
hoedown_buffer_put(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
|
||||
/* HOEDOWN_BUFSETSL: optimized hoedown_buffer_sets of a string literal */
|
||||
#define HOEDOWN_BUFSETSL(output, literal) \
|
||||
hoedown_buffer_set(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
hoedown_buffer_set(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
|
||||
/* HOEDOWN_BUFEQSL: optimized hoedown_buffer_eqs of a string literal */
|
||||
#define HOEDOWN_BUFEQSL(output, literal) \
|
||||
hoedown_buffer_eq(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
hoedown_buffer_eq(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -16,68 +16,68 @@ extern "C" {
|
||||
*************/
|
||||
|
||||
typedef enum hoedown_extensions {
|
||||
/* block-level extensions */
|
||||
HOEDOWN_EXT_TABLES = (1 << 0),
|
||||
HOEDOWN_EXT_FENCED_CODE = (1 << 1),
|
||||
HOEDOWN_EXT_FOOTNOTES = (1 << 2),
|
||||
/* block-level extensions */
|
||||
HOEDOWN_EXT_TABLES = (1 << 0),
|
||||
HOEDOWN_EXT_FENCED_CODE = (1 << 1),
|
||||
HOEDOWN_EXT_FOOTNOTES = (1 << 2),
|
||||
|
||||
/* span-level extensions */
|
||||
HOEDOWN_EXT_AUTOLINK = (1 << 3),
|
||||
HOEDOWN_EXT_STRIKETHROUGH = (1 << 4),
|
||||
HOEDOWN_EXT_UNDERLINE = (1 << 5),
|
||||
HOEDOWN_EXT_HIGHLIGHT = (1 << 6),
|
||||
HOEDOWN_EXT_QUOTE = (1 << 7),
|
||||
HOEDOWN_EXT_SUPERSCRIPT = (1 << 8),
|
||||
HOEDOWN_EXT_MATH = (1 << 9),
|
||||
/* span-level extensions */
|
||||
HOEDOWN_EXT_AUTOLINK = (1 << 3),
|
||||
HOEDOWN_EXT_STRIKETHROUGH = (1 << 4),
|
||||
HOEDOWN_EXT_UNDERLINE = (1 << 5),
|
||||
HOEDOWN_EXT_HIGHLIGHT = (1 << 6),
|
||||
HOEDOWN_EXT_QUOTE = (1 << 7),
|
||||
HOEDOWN_EXT_SUPERSCRIPT = (1 << 8),
|
||||
HOEDOWN_EXT_MATH = (1 << 9),
|
||||
|
||||
/* other flags */
|
||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11),
|
||||
HOEDOWN_EXT_SPACE_HEADERS = (1 << 12),
|
||||
HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13),
|
||||
/* other flags */
|
||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11),
|
||||
HOEDOWN_EXT_SPACE_HEADERS = (1 << 12),
|
||||
HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13),
|
||||
|
||||
/* negative flags */
|
||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14)
|
||||
/* negative flags */
|
||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14)
|
||||
} hoedown_extensions;
|
||||
|
||||
#define HOEDOWN_EXT_BLOCK (\
|
||||
HOEDOWN_EXT_TABLES |\
|
||||
HOEDOWN_EXT_FENCED_CODE |\
|
||||
HOEDOWN_EXT_FOOTNOTES )
|
||||
HOEDOWN_EXT_TABLES |\
|
||||
HOEDOWN_EXT_FENCED_CODE |\
|
||||
HOEDOWN_EXT_FOOTNOTES )
|
||||
|
||||
#define HOEDOWN_EXT_SPAN (\
|
||||
HOEDOWN_EXT_AUTOLINK |\
|
||||
HOEDOWN_EXT_STRIKETHROUGH |\
|
||||
HOEDOWN_EXT_UNDERLINE |\
|
||||
HOEDOWN_EXT_HIGHLIGHT |\
|
||||
HOEDOWN_EXT_QUOTE |\
|
||||
HOEDOWN_EXT_SUPERSCRIPT |\
|
||||
HOEDOWN_EXT_MATH )
|
||||
HOEDOWN_EXT_AUTOLINK |\
|
||||
HOEDOWN_EXT_STRIKETHROUGH |\
|
||||
HOEDOWN_EXT_UNDERLINE |\
|
||||
HOEDOWN_EXT_HIGHLIGHT |\
|
||||
HOEDOWN_EXT_QUOTE |\
|
||||
HOEDOWN_EXT_SUPERSCRIPT |\
|
||||
HOEDOWN_EXT_MATH )
|
||||
|
||||
#define HOEDOWN_EXT_FLAGS (\
|
||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS |\
|
||||
HOEDOWN_EXT_SPACE_HEADERS |\
|
||||
HOEDOWN_EXT_MATH_EXPLICIT )
|
||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS |\
|
||||
HOEDOWN_EXT_SPACE_HEADERS |\
|
||||
HOEDOWN_EXT_MATH_EXPLICIT )
|
||||
|
||||
#define HOEDOWN_EXT_NEGATIVE (\
|
||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE )
|
||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE )
|
||||
|
||||
typedef enum hoedown_list_flags {
|
||||
HOEDOWN_LIST_ORDERED = (1 << 0),
|
||||
HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */
|
||||
HOEDOWN_LIST_ORDERED = (1 << 0),
|
||||
HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */
|
||||
} hoedown_list_flags;
|
||||
|
||||
typedef enum hoedown_table_flags {
|
||||
HOEDOWN_TABLE_ALIGN_LEFT = 1,
|
||||
HOEDOWN_TABLE_ALIGN_RIGHT = 2,
|
||||
HOEDOWN_TABLE_ALIGN_CENTER = 3,
|
||||
HOEDOWN_TABLE_ALIGNMASK = 3,
|
||||
HOEDOWN_TABLE_HEADER = 4
|
||||
HOEDOWN_TABLE_ALIGN_LEFT = 1,
|
||||
HOEDOWN_TABLE_ALIGN_RIGHT = 2,
|
||||
HOEDOWN_TABLE_ALIGN_CENTER = 3,
|
||||
HOEDOWN_TABLE_ALIGNMASK = 3,
|
||||
HOEDOWN_TABLE_HEADER = 4
|
||||
} hoedown_table_flags;
|
||||
|
||||
typedef enum hoedown_autolink_type {
|
||||
HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/
|
||||
HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */
|
||||
HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */
|
||||
HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/
|
||||
HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */
|
||||
HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */
|
||||
} hoedown_autolink_type;
|
||||
|
||||
|
||||
@ -89,57 +89,57 @@ struct hoedown_document;
|
||||
typedef struct hoedown_document hoedown_document;
|
||||
|
||||
struct hoedown_renderer_data {
|
||||
void *opaque;
|
||||
void *opaque;
|
||||
};
|
||||
typedef struct hoedown_renderer_data hoedown_renderer_data;
|
||||
|
||||
/* hoedown_renderer - functions for rendering parsed data */
|
||||
struct hoedown_renderer {
|
||||
/* state object */
|
||||
void *opaque;
|
||||
/* state object */
|
||||
void *opaque;
|
||||
|
||||
/* block level callbacks - NULL skips the block */
|
||||
void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data);
|
||||
void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data);
|
||||
void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
||||
void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
||||
void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
||||
void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data);
|
||||
void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data);
|
||||
void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
/* block level callbacks - NULL skips the block */
|
||||
void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data);
|
||||
void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data);
|
||||
void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
||||
void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
||||
void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
||||
void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data);
|
||||
void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data);
|
||||
void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
|
||||
/* span level callbacks - NULL or return 0 prints the span verbatim */
|
||||
int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data);
|
||||
int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data);
|
||||
int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
||||
int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data);
|
||||
int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data);
|
||||
int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data);
|
||||
int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
/* span level callbacks - NULL or return 0 prints the span verbatim */
|
||||
int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data);
|
||||
int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data);
|
||||
int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
||||
int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data);
|
||||
int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
||||
int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data);
|
||||
int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data);
|
||||
int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
|
||||
/* low level callbacks - NULL copies input directly into the output */
|
||||
void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
/* low level callbacks - NULL copies input directly into the output */
|
||||
void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
||||
|
||||
/* miscellaneous callbacks */
|
||||
void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
||||
void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
||||
/* miscellaneous callbacks */
|
||||
void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
||||
void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
||||
};
|
||||
typedef struct hoedown_renderer hoedown_renderer;
|
||||
|
||||
@ -150,9 +150,9 @@ typedef struct hoedown_renderer hoedown_renderer;
|
||||
|
||||
/* hoedown_document_new: allocate a new document processor instance */
|
||||
hoedown_document *hoedown_document_new(
|
||||
const hoedown_renderer *renderer,
|
||||
hoedown_extensions extensions,
|
||||
size_t max_nesting
|
||||
const hoedown_renderer *renderer,
|
||||
hoedown_extensions extensions,
|
||||
size_t max_nesting
|
||||
) __attribute__ ((malloc));
|
||||
|
||||
/* hoedown_document_render: render regular Markdown using the document processor */
|
||||
|
@ -16,16 +16,16 @@ extern "C" {
|
||||
*************/
|
||||
|
||||
typedef enum hoedown_html_flags {
|
||||
HOEDOWN_HTML_SKIP_HTML = (1 << 0),
|
||||
HOEDOWN_HTML_ESCAPE = (1 << 1),
|
||||
HOEDOWN_HTML_HARD_WRAP = (1 << 2),
|
||||
HOEDOWN_HTML_USE_XHTML = (1 << 3)
|
||||
HOEDOWN_HTML_SKIP_HTML = (1 << 0),
|
||||
HOEDOWN_HTML_ESCAPE = (1 << 1),
|
||||
HOEDOWN_HTML_HARD_WRAP = (1 << 2),
|
||||
HOEDOWN_HTML_USE_XHTML = (1 << 3)
|
||||
} hoedown_html_flags;
|
||||
|
||||
typedef enum hoedown_html_tag {
|
||||
HOEDOWN_HTML_TAG_NONE = 0,
|
||||
HOEDOWN_HTML_TAG_OPEN,
|
||||
HOEDOWN_HTML_TAG_CLOSE
|
||||
HOEDOWN_HTML_TAG_NONE = 0,
|
||||
HOEDOWN_HTML_TAG_OPEN,
|
||||
HOEDOWN_HTML_TAG_CLOSE
|
||||
} hoedown_html_tag;
|
||||
|
||||
|
||||
@ -34,19 +34,19 @@ typedef enum hoedown_html_tag {
|
||||
*********/
|
||||
|
||||
struct hoedown_html_renderer_state {
|
||||
void *opaque;
|
||||
void *opaque;
|
||||
|
||||
struct {
|
||||
int header_count;
|
||||
int current_level;
|
||||
int level_offset;
|
||||
int nesting_level;
|
||||
} toc_data;
|
||||
struct {
|
||||
int header_count;
|
||||
int current_level;
|
||||
int level_offset;
|
||||
int nesting_level;
|
||||
} toc_data;
|
||||
|
||||
hoedown_html_flags flags;
|
||||
hoedown_html_flags flags;
|
||||
|
||||
/* extra callbacks */
|
||||
void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data);
|
||||
/* extra callbacks */
|
||||
void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data);
|
||||
};
|
||||
typedef struct hoedown_html_renderer_state hoedown_html_renderer_state;
|
||||
|
||||
@ -64,13 +64,13 @@ hoedown_html_tag hoedown_html_is_tag(const uint8_t *data, size_t size, const cha
|
||||
|
||||
/* hoedown_html_renderer_new: allocates a regular HTML renderer */
|
||||
hoedown_renderer *hoedown_html_renderer_new(
|
||||
hoedown_html_flags render_flags,
|
||||
int nesting_level
|
||||
hoedown_html_flags render_flags,
|
||||
int nesting_level
|
||||
) __attribute__ ((malloc));
|
||||
|
||||
/* hoedown_html_toc_renderer_new: like hoedown_html_renderer_new, but the returned renderer produces the Table of Contents */
|
||||
hoedown_renderer *hoedown_html_toc_renderer_new(
|
||||
int nesting_level
|
||||
int nesting_level
|
||||
) __attribute__ ((malloc));
|
||||
|
||||
/* hoedown_html_renderer_free: deallocate an HTML renderer */
|
||||
|
@ -15,9 +15,9 @@ extern "C" {
|
||||
*********/
|
||||
|
||||
struct hoedown_stack {
|
||||
void **item;
|
||||
size_t size;
|
||||
size_t asize;
|
||||
void **item;
|
||||
size_t size;
|
||||
size_t asize;
|
||||
};
|
||||
typedef struct hoedown_stack hoedown_stack;
|
||||
|
||||
|
@ -8,274 +8,274 @@
|
||||
#ifndef _MSC_VER
|
||||
#include <strings.h>
|
||||
#else
|
||||
#define strncasecmp _strnicmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
int
|
||||
hoedown_autolink_is_safe(const uint8_t *data, size_t size)
|
||||
{
|
||||
static const size_t valid_uris_count = 6;
|
||||
static const char *valid_uris[] = {
|
||||
"http://", "https://", "/", "#", "ftp://", "mailto:"
|
||||
};
|
||||
static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 };
|
||||
size_t i;
|
||||
static const size_t valid_uris_count = 6;
|
||||
static const char *valid_uris[] = {
|
||||
"http://", "https://", "/", "#", "ftp://", "mailto:"
|
||||
};
|
||||
static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 };
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < valid_uris_count; ++i) {
|
||||
size_t len = valid_uris_size[i];
|
||||
for (i = 0; i < valid_uris_count; ++i) {
|
||||
size_t len = valid_uris_size[i];
|
||||
|
||||
if (size > len &&
|
||||
strncasecmp((char *)data, valid_uris[i], len) == 0 &&
|
||||
isalnum(data[len]))
|
||||
return 1;
|
||||
}
|
||||
if (size > len &&
|
||||
strncasecmp((char *)data, valid_uris[i], len) == 0 &&
|
||||
isalnum(data[len]))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
|
||||
{
|
||||
uint8_t cclose, copen = 0;
|
||||
size_t i;
|
||||
uint8_t cclose, copen = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < link_end; ++i)
|
||||
if (data[i] == '<') {
|
||||
link_end = i;
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < link_end; ++i)
|
||||
if (data[i] == '<') {
|
||||
link_end = i;
|
||||
break;
|
||||
}
|
||||
|
||||
while (link_end > 0) {
|
||||
if (strchr("?!.,:", data[link_end - 1]) != NULL)
|
||||
link_end--;
|
||||
while (link_end > 0) {
|
||||
if (strchr("?!.,:", data[link_end - 1]) != NULL)
|
||||
link_end--;
|
||||
|
||||
else if (data[link_end - 1] == ';') {
|
||||
size_t new_end = link_end - 2;
|
||||
else if (data[link_end - 1] == ';') {
|
||||
size_t new_end = link_end - 2;
|
||||
|
||||
while (new_end > 0 && isalpha(data[new_end]))
|
||||
new_end--;
|
||||
while (new_end > 0 && isalpha(data[new_end]))
|
||||
new_end--;
|
||||
|
||||
if (new_end < link_end - 2 && data[new_end] == '&')
|
||||
link_end = new_end;
|
||||
else
|
||||
link_end--;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (new_end < link_end - 2 && data[new_end] == '&')
|
||||
link_end = new_end;
|
||||
else
|
||||
link_end--;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
|
||||
cclose = data[link_end - 1];
|
||||
cclose = data[link_end - 1];
|
||||
|
||||
switch (cclose) {
|
||||
case '"': copen = '"'; break;
|
||||
case '\'': copen = '\''; break;
|
||||
case ')': copen = '('; break;
|
||||
case ']': copen = '['; break;
|
||||
case '}': copen = '{'; break;
|
||||
}
|
||||
switch (cclose) {
|
||||
case '"': copen = '"'; break;
|
||||
case '\'': copen = '\''; break;
|
||||
case ')': copen = '('; break;
|
||||
case ']': copen = '['; break;
|
||||
case '}': copen = '{'; break;
|
||||
}
|
||||
|
||||
if (copen != 0) {
|
||||
size_t closing = 0;
|
||||
size_t opening = 0;
|
||||
size_t i = 0;
|
||||
if (copen != 0) {
|
||||
size_t closing = 0;
|
||||
size_t opening = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* Try to close the final punctuation sign in this same line;
|
||||
* if we managed to close it outside of the URL, that means that it's
|
||||
* not part of the URL. If it closes inside the URL, that means it
|
||||
* is part of the URL.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* foo http://www.pokemon.com/Pikachu_(Electric) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
||||
*
|
||||
* foo (http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
||||
*
|
||||
* foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric))
|
||||
*
|
||||
* (foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => foo http://www.pokemon.com/Pikachu_(Electric)
|
||||
*/
|
||||
/* Try to close the final punctuation sign in this same line;
|
||||
* if we managed to close it outside of the URL, that means that it's
|
||||
* not part of the URL. If it closes inside the URL, that means it
|
||||
* is part of the URL.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* foo http://www.pokemon.com/Pikachu_(Electric) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
||||
*
|
||||
* foo (http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
||||
*
|
||||
* foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => http://www.pokemon.com/Pikachu_(Electric))
|
||||
*
|
||||
* (foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
||||
* => foo http://www.pokemon.com/Pikachu_(Electric)
|
||||
*/
|
||||
|
||||
while (i < link_end) {
|
||||
if (data[i] == copen)
|
||||
opening++;
|
||||
else if (data[i] == cclose)
|
||||
closing++;
|
||||
while (i < link_end) {
|
||||
if (data[i] == copen)
|
||||
opening++;
|
||||
else if (data[i] == cclose)
|
||||
closing++;
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (closing != opening)
|
||||
link_end--;
|
||||
}
|
||||
if (closing != opening)
|
||||
link_end--;
|
||||
}
|
||||
|
||||
return link_end;
|
||||
return link_end;
|
||||
}
|
||||
|
||||
static size_t
|
||||
check_domain(uint8_t *data, size_t size, int allow_short)
|
||||
{
|
||||
size_t i, np = 0;
|
||||
size_t i, np = 0;
|
||||
|
||||
if (!isalnum(data[0]))
|
||||
return 0;
|
||||
if (!isalnum(data[0]))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < size - 1; ++i) {
|
||||
if (strchr(".:", data[i]) != NULL) np++;
|
||||
else if (!isalnum(data[i]) && data[i] != '-') break;
|
||||
}
|
||||
for (i = 1; i < size - 1; ++i) {
|
||||
if (strchr(".:", data[i]) != NULL) np++;
|
||||
else if (!isalnum(data[i]) && data[i] != '-') break;
|
||||
}
|
||||
|
||||
if (allow_short) {
|
||||
/* We don't need a valid domain in the strict sense (with
|
||||
* least one dot; so just make sure it's composed of valid
|
||||
* domain characters and return the length of the the valid
|
||||
* sequence. */
|
||||
return i;
|
||||
} else {
|
||||
/* a valid domain needs to have at least a dot.
|
||||
* that's as far as we get */
|
||||
return np ? i : 0;
|
||||
}
|
||||
if (allow_short) {
|
||||
/* We don't need a valid domain in the strict sense (with
|
||||
* least one dot; so just make sure it's composed of valid
|
||||
* domain characters and return the length of the the valid
|
||||
* sequence. */
|
||||
return i;
|
||||
} else {
|
||||
/* a valid domain needs to have at least a dot.
|
||||
* that's as far as we get */
|
||||
return np ? i : 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
hoedown_autolink__www(
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
{
|
||||
size_t link_end;
|
||||
size_t link_end;
|
||||
|
||||
if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
|
||||
return 0;
|
||||
if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
|
||||
return 0;
|
||||
|
||||
if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
|
||||
return 0;
|
||||
if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
|
||||
return 0;
|
||||
|
||||
link_end = check_domain(data, size, 0);
|
||||
link_end = check_domain(data, size, 0);
|
||||
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
|
||||
while (link_end < size && !isspace(data[link_end]))
|
||||
link_end++;
|
||||
while (link_end < size && !isspace(data[link_end]))
|
||||
link_end++;
|
||||
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
|
||||
hoedown_buffer_put(link, data, link_end);
|
||||
*rewind_p = 0;
|
||||
hoedown_buffer_put(link, data, link_end);
|
||||
*rewind_p = 0;
|
||||
|
||||
return (int)link_end;
|
||||
return (int)link_end;
|
||||
}
|
||||
|
||||
size_t
|
||||
hoedown_autolink__email(
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
{
|
||||
size_t link_end, rewind;
|
||||
int nb = 0, np = 0;
|
||||
size_t link_end, rewind;
|
||||
int nb = 0, np = 0;
|
||||
|
||||
for (rewind = 0; rewind < max_rewind; ++rewind) {
|
||||
uint8_t c = data[-1 - rewind];
|
||||
for (rewind = 0; rewind < max_rewind; ++rewind) {
|
||||
uint8_t c = data[-1 - rewind];
|
||||
|
||||
if (isalnum(c))
|
||||
continue;
|
||||
if (isalnum(c))
|
||||
continue;
|
||||
|
||||
if (strchr(".+-_", c) != NULL)
|
||||
continue;
|
||||
if (strchr(".+-_", c) != NULL)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rewind == 0)
|
||||
return 0;
|
||||
if (rewind == 0)
|
||||
return 0;
|
||||
|
||||
for (link_end = 0; link_end < size; ++link_end) {
|
||||
uint8_t c = data[link_end];
|
||||
for (link_end = 0; link_end < size; ++link_end) {
|
||||
uint8_t c = data[link_end];
|
||||
|
||||
if (isalnum(c))
|
||||
continue;
|
||||
if (isalnum(c))
|
||||
continue;
|
||||
|
||||
if (c == '@')
|
||||
nb++;
|
||||
else if (c == '.' && link_end < size - 1)
|
||||
np++;
|
||||
else if (c != '-' && c != '_')
|
||||
break;
|
||||
}
|
||||
if (c == '@')
|
||||
nb++;
|
||||
else if (c == '.' && link_end < size - 1)
|
||||
np++;
|
||||
else if (c != '-' && c != '_')
|
||||
break;
|
||||
}
|
||||
|
||||
if (link_end < 2 || nb != 1 || np == 0 ||
|
||||
!isalpha(data[link_end - 1]))
|
||||
return 0;
|
||||
if (link_end < 2 || nb != 1 || np == 0 ||
|
||||
!isalpha(data[link_end - 1]))
|
||||
return 0;
|
||||
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
|
||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
||||
*rewind_p = rewind;
|
||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
||||
*rewind_p = rewind;
|
||||
|
||||
return link_end;
|
||||
return link_end;
|
||||
}
|
||||
|
||||
size_t
|
||||
hoedown_autolink__url(
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
size_t *rewind_p,
|
||||
hoedown_buffer *link,
|
||||
uint8_t *data,
|
||||
size_t max_rewind,
|
||||
size_t size,
|
||||
unsigned int flags)
|
||||
{
|
||||
size_t link_end, rewind = 0, domain_len;
|
||||
size_t link_end, rewind = 0, domain_len;
|
||||
|
||||
if (size < 4 || data[1] != '/' || data[2] != '/')
|
||||
return 0;
|
||||
if (size < 4 || data[1] != '/' || data[2] != '/')
|
||||
return 0;
|
||||
|
||||
while (rewind < max_rewind && isalpha(data[-1 - rewind]))
|
||||
rewind++;
|
||||
while (rewind < max_rewind && isalpha(data[-1 - rewind]))
|
||||
rewind++;
|
||||
|
||||
if (!hoedown_autolink_is_safe(data - rewind, size + rewind))
|
||||
return 0;
|
||||
if (!hoedown_autolink_is_safe(data - rewind, size + rewind))
|
||||
return 0;
|
||||
|
||||
link_end = strlen("://");
|
||||
link_end = strlen("://");
|
||||
|
||||
domain_len = check_domain(
|
||||
data + link_end,
|
||||
size - link_end,
|
||||
flags & HOEDOWN_AUTOLINK_SHORT_DOMAINS);
|
||||
domain_len = check_domain(
|
||||
data + link_end,
|
||||
size - link_end,
|
||||
flags & HOEDOWN_AUTOLINK_SHORT_DOMAINS);
|
||||
|
||||
if (domain_len == 0)
|
||||
return 0;
|
||||
if (domain_len == 0)
|
||||
return 0;
|
||||
|
||||
link_end += domain_len;
|
||||
while (link_end < size && !isspace(data[link_end]))
|
||||
link_end++;
|
||||
link_end += domain_len;
|
||||
while (link_end < size && !isspace(data[link_end]))
|
||||
link_end++;
|
||||
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
||||
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
if (link_end == 0)
|
||||
return 0;
|
||||
|
||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
||||
*rewind_p = rewind;
|
||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
||||
*rewind_p = rewind;
|
||||
|
||||
return link_end;
|
||||
return link_end;
|
||||
}
|
||||
|
@ -8,301 +8,301 @@
|
||||
void *
|
||||
hoedown_malloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
void *ret = malloc(size);
|
||||
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
hoedown_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ret = calloc(nmemb, size);
|
||||
void *ret = calloc(nmemb, size);
|
||||
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
hoedown_realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
void *ret = realloc(ptr, size);
|
||||
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
if (!ret) {
|
||||
fprintf(stderr, "Allocation failed.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_init(
|
||||
hoedown_buffer *buf,
|
||||
size_t unit,
|
||||
hoedown_realloc_callback data_realloc,
|
||||
hoedown_free_callback data_free,
|
||||
hoedown_free_callback buffer_free)
|
||||
hoedown_buffer *buf,
|
||||
size_t unit,
|
||||
hoedown_realloc_callback data_realloc,
|
||||
hoedown_free_callback data_free,
|
||||
hoedown_free_callback buffer_free)
|
||||
{
|
||||
assert(buf);
|
||||
assert(buf);
|
||||
|
||||
buf->data = NULL;
|
||||
buf->size = buf->asize = 0;
|
||||
buf->unit = unit;
|
||||
buf->data_realloc = data_realloc;
|
||||
buf->data_free = data_free;
|
||||
buf->buffer_free = buffer_free;
|
||||
buf->data = NULL;
|
||||
buf->size = buf->asize = 0;
|
||||
buf->unit = unit;
|
||||
buf->data_realloc = data_realloc;
|
||||
buf->data_free = data_free;
|
||||
buf->buffer_free = buffer_free;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_uninit(hoedown_buffer *buf)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
buf->data_free(buf->data);
|
||||
assert(buf && buf->unit);
|
||||
buf->data_free(buf->data);
|
||||
}
|
||||
|
||||
hoedown_buffer *
|
||||
hoedown_buffer_new(size_t unit)
|
||||
{
|
||||
hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer));
|
||||
hoedown_buffer_init(ret, unit, hoedown_realloc, free, free);
|
||||
return ret;
|
||||
hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer));
|
||||
hoedown_buffer_init(ret, unit, hoedown_realloc, free, free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_free(hoedown_buffer *buf)
|
||||
{
|
||||
if (!buf) return;
|
||||
assert(buf && buf->unit);
|
||||
if (!buf) return;
|
||||
assert(buf && buf->unit);
|
||||
|
||||
buf->data_free(buf->data);
|
||||
buf->data_free(buf->data);
|
||||
|
||||
if (buf->buffer_free)
|
||||
buf->buffer_free(buf);
|
||||
if (buf->buffer_free)
|
||||
buf->buffer_free(buf);
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_reset(hoedown_buffer *buf)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
buf->data_free(buf->data);
|
||||
buf->data = NULL;
|
||||
buf->size = buf->asize = 0;
|
||||
buf->data_free(buf->data);
|
||||
buf->data = NULL;
|
||||
buf->size = buf->asize = 0;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz)
|
||||
{
|
||||
size_t neoasz;
|
||||
assert(buf && buf->unit);
|
||||
size_t neoasz;
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (buf->asize >= neosz)
|
||||
return;
|
||||
if (buf->asize >= neosz)
|
||||
return;
|
||||
|
||||
neoasz = buf->asize + buf->unit;
|
||||
while (neoasz < neosz)
|
||||
neoasz += buf->unit;
|
||||
neoasz = buf->asize + buf->unit;
|
||||
while (neoasz < neosz)
|
||||
neoasz += buf->unit;
|
||||
|
||||
buf->data = (uint8_t *) buf->data_realloc(buf->data, neoasz);
|
||||
buf->asize = neoasz;
|
||||
buf->data = (uint8_t *) buf->data_realloc(buf->data, neoasz);
|
||||
buf->asize = neoasz;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (buf->size + size > buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + size);
|
||||
if (buf->size + size > buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + size);
|
||||
|
||||
memcpy(buf->data + buf->size, data, size);
|
||||
buf->size += size;
|
||||
memcpy(buf->data + buf->size, data, size);
|
||||
buf->size += size;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_puts(hoedown_buffer *buf, const char *str)
|
||||
{
|
||||
hoedown_buffer_put(buf, (const uint8_t *)str, strlen(str));
|
||||
hoedown_buffer_put(buf, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (buf->size >= buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
if (buf->size >= buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
|
||||
buf->data[buf->size] = c;
|
||||
buf->size += 1;
|
||||
buf->data[buf->size] = c;
|
||||
buf->size += 1;
|
||||
}
|
||||
|
||||
int
|
||||
hoedown_buffer_putf(hoedown_buffer *buf, FILE *file)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
while (!(feof(file) || ferror(file))) {
|
||||
hoedown_buffer_grow(buf, buf->size + buf->unit);
|
||||
buf->size += fread(buf->data + buf->size, 1, buf->unit, file);
|
||||
}
|
||||
while (!(feof(file) || ferror(file))) {
|
||||
hoedown_buffer_grow(buf, buf->size + buf->unit);
|
||||
buf->size += fread(buf->data + buf->size, 1, buf->unit, file);
|
||||
}
|
||||
|
||||
return ferror(file);
|
||||
return ferror(file);
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (size > buf->asize)
|
||||
hoedown_buffer_grow(buf, size);
|
||||
if (size > buf->asize)
|
||||
hoedown_buffer_grow(buf, size);
|
||||
|
||||
memcpy(buf->data, data, size);
|
||||
buf->size = size;
|
||||
memcpy(buf->data, data, size);
|
||||
buf->size = size;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_sets(hoedown_buffer *buf, const char *str)
|
||||
{
|
||||
hoedown_buffer_set(buf, (const uint8_t *)str, strlen(str));
|
||||
hoedown_buffer_set(buf, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
int
|
||||
hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size)
|
||||
{
|
||||
if (buf->size != size) return 0;
|
||||
return memcmp(buf->data, data, size) == 0;
|
||||
if (buf->size != size) return 0;
|
||||
return memcmp(buf->data, data, size) == 0;
|
||||
}
|
||||
|
||||
int
|
||||
hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str)
|
||||
{
|
||||
return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str));
|
||||
return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
int
|
||||
hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
|
||||
{
|
||||
size_t i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < buf->size; ++i) {
|
||||
if (prefix[i] == 0)
|
||||
return 0;
|
||||
for (i = 0; i < buf->size; ++i) {
|
||||
if (prefix[i] == 0)
|
||||
return 0;
|
||||
|
||||
if (buf->data[i] != prefix[i])
|
||||
return buf->data[i] - prefix[i];
|
||||
}
|
||||
if (buf->data[i] != prefix[i])
|
||||
return buf->data[i] - prefix[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_slurp(hoedown_buffer *buf, size_t size)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (size >= buf->size) {
|
||||
buf->size = 0;
|
||||
return;
|
||||
}
|
||||
if (size >= buf->size) {
|
||||
buf->size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
buf->size -= size;
|
||||
memmove(buf->data, buf->data + size, buf->size);
|
||||
buf->size -= size;
|
||||
memmove(buf->data, buf->data + size, buf->size);
|
||||
}
|
||||
|
||||
const char *
|
||||
hoedown_buffer_cstr(hoedown_buffer *buf)
|
||||
{
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (buf->size < buf->asize && buf->data[buf->size] == 0)
|
||||
return (char *)buf->data;
|
||||
if (buf->size < buf->asize && buf->data[buf->size] == 0)
|
||||
return (char *)buf->data;
|
||||
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
buf->data[buf->size] = 0;
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
buf->data[buf->size] = 0;
|
||||
|
||||
return (char *)buf->data;
|
||||
return (char *)buf->data;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (buf->size >= buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
if (buf->size >= buf->asize)
|
||||
hoedown_buffer_grow(buf, buf->size + 1);
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0) {
|
||||
if (n < 0) {
|
||||
#ifndef _MSC_VER
|
||||
return;
|
||||
return;
|
||||
#else
|
||||
va_start(ap, fmt);
|
||||
n = _vscprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
n = _vscprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((size_t)n >= buf->asize - buf->size) {
|
||||
hoedown_buffer_grow(buf, buf->size + n + 1);
|
||||
if ((size_t)n >= buf->asize - buf->size) {
|
||||
hoedown_buffer_grow(buf, buf->size + n + 1);
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
return;
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
buf->size += n;
|
||||
buf->size += n;
|
||||
}
|
||||
|
||||
void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int c) {
|
||||
unsigned char unichar[4];
|
||||
unsigned char unichar[4];
|
||||
|
||||
assert(buf && buf->unit);
|
||||
assert(buf && buf->unit);
|
||||
|
||||
if (c < 0x80) {
|
||||
hoedown_buffer_putc(buf, c);
|
||||
}
|
||||
else if (c < 0x800) {
|
||||
unichar[0] = 192 + (c / 64);
|
||||
unichar[1] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 2);
|
||||
}
|
||||
else if (c - 0xd800u < 0x800) {
|
||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
||||
}
|
||||
else if (c < 0x10000) {
|
||||
unichar[0] = 224 + (c / 4096);
|
||||
unichar[1] = 128 + (c / 64) % 64;
|
||||
unichar[2] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 3);
|
||||
}
|
||||
else if (c < 0x110000) {
|
||||
unichar[0] = 240 + (c / 262144);
|
||||
unichar[1] = 128 + (c / 4096) % 64;
|
||||
unichar[2] = 128 + (c / 64) % 64;
|
||||
unichar[3] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 4);
|
||||
}
|
||||
else {
|
||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
||||
}
|
||||
if (c < 0x80) {
|
||||
hoedown_buffer_putc(buf, c);
|
||||
}
|
||||
else if (c < 0x800) {
|
||||
unichar[0] = 192 + (c / 64);
|
||||
unichar[1] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 2);
|
||||
}
|
||||
else if (c - 0xd800u < 0x800) {
|
||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
||||
}
|
||||
else if (c < 0x10000) {
|
||||
unichar[0] = 224 + (c / 4096);
|
||||
unichar[1] = 128 + (c / 64) % 64;
|
||||
unichar[2] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 3);
|
||||
}
|
||||
else if (c < 0x110000) {
|
||||
unichar[0] = 240 + (c / 262144);
|
||||
unichar[1] = 128 + (c / 4096) % 64;
|
||||
unichar[2] = 128 + (c / 64) % 64;
|
||||
unichar[3] = 128 + (c % 64);
|
||||
hoedown_buffer_put(buf, unichar, 4);
|
||||
}
|
||||
else {
|
||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,13 +12,13 @@
|
||||
/*
|
||||
* The following characters will not be escaped:
|
||||
*
|
||||
* -_.+!*'(),%#@?=;:/,+&$ alphanum
|
||||
* -_.+!*'(),%#@?=;:/,+&$ alphanum
|
||||
*
|
||||
* Note that this character set is the addition of:
|
||||
*
|
||||
* - The characters which are safe to be in an URL
|
||||
* - The characters which are *not* safe to be in
|
||||
* an URL because they are RESERVED characters.
|
||||
* - The characters which are safe to be in an URL
|
||||
* - The characters which are *not* safe to be in
|
||||
* an URL because they are RESERVED characters.
|
||||
*
|
||||
* We assume (lazily) that any RESERVED char that
|
||||
* appears inside an URL is actually meant to
|
||||
@ -35,84 +35,84 @@
|
||||
*
|
||||
*/
|
||||
static const uint8_t HREF_SAFE[UINT8_MAX+1] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
void
|
||||
hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size)
|
||||
{
|
||||
static const char hex_chars[] = "0123456789ABCDEF";
|
||||
size_t i = 0, mark;
|
||||
char hex_str[3];
|
||||
static const char hex_chars[] = "0123456789ABCDEF";
|
||||
size_t i = 0, mark;
|
||||
char hex_str[3];
|
||||
|
||||
hex_str[0] = '%';
|
||||
hex_str[0] = '%';
|
||||
|
||||
while (i < size) {
|
||||
mark = i;
|
||||
while (i < size && HREF_SAFE[data[i]]) i++;
|
||||
while (i < size) {
|
||||
mark = i;
|
||||
while (i < size && HREF_SAFE[data[i]]) i++;
|
||||
|
||||
/* Optimization for cases where there's nothing to escape */
|
||||
if (mark == 0 && i >= size) {
|
||||
hoedown_buffer_put(ob, data, size);
|
||||
return;
|
||||
}
|
||||
/* Optimization for cases where there's nothing to escape */
|
||||
if (mark == 0 && i >= size) {
|
||||
hoedown_buffer_put(ob, data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (likely(i > mark)) {
|
||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
||||
}
|
||||
if (likely(i > mark)) {
|
||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
||||
}
|
||||
|
||||
/* escaping */
|
||||
if (i >= size)
|
||||
break;
|
||||
/* escaping */
|
||||
if (i >= size)
|
||||
break;
|
||||
|
||||
switch (data[i]) {
|
||||
/* amp appears all the time in URLs, but needs
|
||||
* HTML-entity escaping to be inside an href */
|
||||
case '&':
|
||||
HOEDOWN_BUFPUTSL(ob, "&");
|
||||
break;
|
||||
switch (data[i]) {
|
||||
/* amp appears all the time in URLs, but needs
|
||||
* HTML-entity escaping to be inside an href */
|
||||
case '&':
|
||||
HOEDOWN_BUFPUTSL(ob, "&");
|
||||
break;
|
||||
|
||||
/* the single quote is a valid URL character
|
||||
* according to the standard; it needs HTML
|
||||
* entity escaping too */
|
||||
case '\'':
|
||||
HOEDOWN_BUFPUTSL(ob, "'");
|
||||
break;
|
||||
/* the single quote is a valid URL character
|
||||
* according to the standard; it needs HTML
|
||||
* entity escaping too */
|
||||
case '\'':
|
||||
HOEDOWN_BUFPUTSL(ob, "'");
|
||||
break;
|
||||
|
||||
/* the space can be escaped to %20 or a plus
|
||||
* sign. we're going with the generic escape
|
||||
* for now. the plus thing is more commonly seen
|
||||
* when building GET strings */
|
||||
/* the space can be escaped to %20 or a plus
|
||||
* sign. we're going with the generic escape
|
||||
* for now. the plus thing is more commonly seen
|
||||
* when building GET strings */
|
||||
#if 0
|
||||
case ' ':
|
||||
hoedown_buffer_putc(ob, '+');
|
||||
break;
|
||||
case ' ':
|
||||
hoedown_buffer_putc(ob, '+');
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* every other character goes with a %XX escaping */
|
||||
default:
|
||||
hex_str[1] = hex_chars[(data[i] >> 4) & 0xF];
|
||||
hex_str[2] = hex_chars[data[i] & 0xF];
|
||||
hoedown_buffer_put(ob, (uint8_t *)hex_str, 3);
|
||||
}
|
||||
/* every other character goes with a %XX escaping */
|
||||
default:
|
||||
hex_str[1] = hex_chars[(data[i] >> 4) & 0xF];
|
||||
hex_str[2] = hex_chars[data[i] & 0xF];
|
||||
hoedown_buffer_put(ob, (uint8_t *)hex_str, 3);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -128,22 +128,22 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size)
|
||||
*
|
||||
*/
|
||||
static const uint8_t HTML_ESCAPE_TABLE[UINT8_MAX+1] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static const char *HTML_ESCAPES[] = {
|
||||
@ -159,30 +159,30 @@ static const char *HTML_ESCAPES[] = {
|
||||
void
|
||||
hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure)
|
||||
{
|
||||
size_t i = 0, mark;
|
||||
size_t i = 0, mark;
|
||||
|
||||
while (1) {
|
||||
mark = i;
|
||||
while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++;
|
||||
while (1) {
|
||||
mark = i;
|
||||
while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++;
|
||||
|
||||
/* Optimization for cases where there's nothing to escape */
|
||||
if (mark == 0 && i >= size) {
|
||||
hoedown_buffer_put(ob, data, size);
|
||||
return;
|
||||
}
|
||||
/* Optimization for cases where there's nothing to escape */
|
||||
if (mark == 0 && i >= size) {
|
||||
hoedown_buffer_put(ob, data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (likely(i > mark))
|
||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
||||
if (likely(i > mark))
|
||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
||||
|
||||
if (i >= size) break;
|
||||
if (i >= size) break;
|
||||
|
||||
/* The forward slash is only escaped in secure mode */
|
||||
if (!secure && data[i] == '/') {
|
||||
hoedown_buffer_putc(ob, '/');
|
||||
} else {
|
||||
hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]);
|
||||
}
|
||||
/* The forward slash is only escaped in secure mode */
|
||||
if (!secure && data[i] == '/') {
|
||||
hoedown_buffer_putc(ob, '/');
|
||||
} else {
|
||||
hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,8 +10,8 @@
|
||||
#endif
|
||||
|
||||
struct smartypants_data {
|
||||
int in_squote;
|
||||
int in_dquote;
|
||||
int in_squote;
|
||||
int in_dquote;
|
||||
};
|
||||
|
||||
static size_t smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
||||
@ -26,353 +26,353 @@ static size_t smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_da
|
||||
static size_t smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
||||
|
||||
static size_t (*smartypants_cb_ptrs[])
|
||||
(hoedown_buffer *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) =
|
||||
(hoedown_buffer *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) =
|
||||
{
|
||||
NULL, /* 0 */
|
||||
smartypants_cb__dash, /* 1 */
|
||||
smartypants_cb__parens, /* 2 */
|
||||
smartypants_cb__squote, /* 3 */
|
||||
smartypants_cb__dquote, /* 4 */
|
||||
smartypants_cb__amp, /* 5 */
|
||||
smartypants_cb__period, /* 6 */
|
||||
smartypants_cb__number, /* 7 */
|
||||
smartypants_cb__ltag, /* 8 */
|
||||
smartypants_cb__backtick, /* 9 */
|
||||
smartypants_cb__escape, /* 10 */
|
||||
NULL, /* 0 */
|
||||
smartypants_cb__dash, /* 1 */
|
||||
smartypants_cb__parens, /* 2 */
|
||||
smartypants_cb__squote, /* 3 */
|
||||
smartypants_cb__dquote, /* 4 */
|
||||
smartypants_cb__amp, /* 5 */
|
||||
smartypants_cb__period, /* 6 */
|
||||
smartypants_cb__number, /* 7 */
|
||||
smartypants_cb__ltag, /* 8 */
|
||||
smartypants_cb__backtick, /* 9 */
|
||||
smartypants_cb__escape, /* 10 */
|
||||
};
|
||||
|
||||
static const uint8_t smartypants_cb_chars[UINT8_MAX+1] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0,
|
||||
0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0,
|
||||
0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static int
|
||||
word_boundary(uint8_t c)
|
||||
{
|
||||
return c == 0 || isspace(c) || ispunct(c);
|
||||
return c == 0 || isspace(c) || ispunct(c);
|
||||
}
|
||||
|
||||
/*
|
||||
If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.),
|
||||
returns the length of the sequence of characters that makes up the single-
|
||||
quote. Otherwise, returns zero.
|
||||
If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.),
|
||||
returns the length of the sequence of characters that makes up the single-
|
||||
quote. Otherwise, returns zero.
|
||||
*/
|
||||
static size_t
|
||||
squote_len(const uint8_t *text, size_t size)
|
||||
{
|
||||
static char* single_quote_list[] = { "'", "'", "'", "'", NULL };
|
||||
char** p;
|
||||
static char* single_quote_list[] = { "'", "'", "'", "'", NULL };
|
||||
char** p;
|
||||
|
||||
for (p = single_quote_list; *p; ++p) {
|
||||
size_t len = strlen(*p);
|
||||
if (size >= len && memcmp(text, *p, len) == 0) {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
for (p = single_quote_list; *p; ++p) {
|
||||
size_t len = strlen(*p);
|
||||
if (size >= len && memcmp(text, *p, len) == 0) {
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts " or ' at very beginning or end of a word to left or right quote */
|
||||
static int
|
||||
smartypants_quotes(hoedown_buffer *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open)
|
||||
{
|
||||
char ent[8];
|
||||
char ent[8];
|
||||
|
||||
if (*is_open && !word_boundary(next_char))
|
||||
return 0;
|
||||
if (*is_open && !word_boundary(next_char))
|
||||
return 0;
|
||||
|
||||
if (!(*is_open) && !word_boundary(previous_char))
|
||||
return 0;
|
||||
if (!(*is_open) && !word_boundary(previous_char))
|
||||
return 0;
|
||||
|
||||
snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote);
|
||||
*is_open = !(*is_open);
|
||||
hoedown_buffer_puts(ob, ent);
|
||||
return 1;
|
||||
snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote);
|
||||
*is_open = !(*is_open);
|
||||
hoedown_buffer_puts(ob, ent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Converts ' to left or right single quote; but the initial ' might be in
|
||||
different forms, e.g. ' or ' or '.
|
||||
'squote_text' points to the original single quote, and 'squote_size' is its length.
|
||||
'text' points at the last character of the single-quote, e.g. ' or ;
|
||||
Converts ' to left or right single quote; but the initial ' might be in
|
||||
different forms, e.g. ' or ' or '.
|
||||
'squote_text' points to the original single quote, and 'squote_size' is its length.
|
||||
'text' points at the last character of the single-quote, e.g. ' or ;
|
||||
*/
|
||||
static size_t
|
||||
smartypants_squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size,
|
||||
const uint8_t *squote_text, size_t squote_size)
|
||||
const uint8_t *squote_text, size_t squote_size)
|
||||
{
|
||||
if (size >= 2) {
|
||||
uint8_t t1 = tolower(text[1]);
|
||||
size_t next_squote_len = squote_len(text+1, size-1);
|
||||
if (size >= 2) {
|
||||
uint8_t t1 = tolower(text[1]);
|
||||
size_t next_squote_len = squote_len(text+1, size-1);
|
||||
|
||||
/* convert '' to “ or ” */
|
||||
if (next_squote_len > 0) {
|
||||
uint8_t next_char = (size > 1+next_squote_len) ? text[1+next_squote_len] : 0;
|
||||
if (smartypants_quotes(ob, previous_char, next_char, 'd', &smrt->in_dquote))
|
||||
return next_squote_len;
|
||||
}
|
||||
/* convert '' to “ or ” */
|
||||
if (next_squote_len > 0) {
|
||||
uint8_t next_char = (size > 1+next_squote_len) ? text[1+next_squote_len] : 0;
|
||||
if (smartypants_quotes(ob, previous_char, next_char, 'd', &smrt->in_dquote))
|
||||
return next_squote_len;
|
||||
}
|
||||
|
||||
/* Tom's, isn't, I'm, I'd */
|
||||
if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') &&
|
||||
(size == 3 || word_boundary(text[2]))) {
|
||||
HOEDOWN_BUFPUTSL(ob, "’");
|
||||
return 0;
|
||||
}
|
||||
/* Tom's, isn't, I'm, I'd */
|
||||
if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') &&
|
||||
(size == 3 || word_boundary(text[2]))) {
|
||||
HOEDOWN_BUFPUTSL(ob, "’");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* you're, you'll, you've */
|
||||
if (size >= 3) {
|
||||
uint8_t t2 = tolower(text[2]);
|
||||
/* you're, you'll, you've */
|
||||
if (size >= 3) {
|
||||
uint8_t t2 = tolower(text[2]);
|
||||
|
||||
if (((t1 == 'r' && t2 == 'e') ||
|
||||
(t1 == 'l' && t2 == 'l') ||
|
||||
(t1 == 'v' && t2 == 'e')) &&
|
||||
(size == 4 || word_boundary(text[3]))) {
|
||||
HOEDOWN_BUFPUTSL(ob, "’");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (((t1 == 'r' && t2 == 'e') ||
|
||||
(t1 == 'l' && t2 == 'l') ||
|
||||
(t1 == 'v' && t2 == 'e')) &&
|
||||
(size == 4 || word_boundary(text[3]))) {
|
||||
HOEDOWN_BUFPUTSL(ob, "’");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
||||
return 0;
|
||||
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
||||
return 0;
|
||||
|
||||
hoedown_buffer_put(ob, squote_text, squote_size);
|
||||
return 0;
|
||||
hoedown_buffer_put(ob, squote_text, squote_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts ' to left or right single quote. */
|
||||
static size_t
|
||||
smartypants_cb__squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
return smartypants_squote(ob, smrt, previous_char, text, size, text, 1);
|
||||
return smartypants_squote(ob, smrt, previous_char, text, size, text, 1);
|
||||
}
|
||||
|
||||
/* Converts (c), (r), (tm) */
|
||||
static size_t
|
||||
smartypants_cb__parens(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (size >= 3) {
|
||||
uint8_t t1 = tolower(text[1]);
|
||||
uint8_t t2 = tolower(text[2]);
|
||||
if (size >= 3) {
|
||||
uint8_t t1 = tolower(text[1]);
|
||||
uint8_t t2 = tolower(text[2]);
|
||||
|
||||
if (t1 == 'c' && t2 == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "©");
|
||||
return 2;
|
||||
}
|
||||
if (t1 == 'c' && t2 == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "©");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (t1 == 'r' && t2 == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "®");
|
||||
return 2;
|
||||
}
|
||||
if (t1 == 'r' && t2 == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "®");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "™");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') {
|
||||
HOEDOWN_BUFPUTSL(ob, "™");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts "--" to em-dash, etc. */
|
||||
static size_t
|
||||
smartypants_cb__dash(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (size >= 3 && text[1] == '-' && text[2] == '-') {
|
||||
HOEDOWN_BUFPUTSL(ob, "—");
|
||||
return 2;
|
||||
}
|
||||
if (size >= 3 && text[1] == '-' && text[2] == '-') {
|
||||
HOEDOWN_BUFPUTSL(ob, "—");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (size >= 2 && text[1] == '-') {
|
||||
HOEDOWN_BUFPUTSL(ob, "–");
|
||||
return 1;
|
||||
}
|
||||
if (size >= 2 && text[1] == '-') {
|
||||
HOEDOWN_BUFPUTSL(ob, "–");
|
||||
return 1;
|
||||
}
|
||||
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts " etc. */
|
||||
static size_t
|
||||
smartypants_cb__amp(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
size_t len;
|
||||
if (size >= 6 && memcmp(text, """, 6) == 0) {
|
||||
if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote))
|
||||
return 5;
|
||||
}
|
||||
size_t len;
|
||||
if (size >= 6 && memcmp(text, """, 6) == 0) {
|
||||
if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote))
|
||||
return 5;
|
||||
}
|
||||
|
||||
len = squote_len(text, size);
|
||||
if (len > 0) {
|
||||
return (len-1) + smartypants_squote(ob, smrt, previous_char, text+(len-1), size-(len-1), text, len);
|
||||
}
|
||||
len = squote_len(text, size);
|
||||
if (len > 0) {
|
||||
return (len-1) + smartypants_squote(ob, smrt, previous_char, text+(len-1), size-(len-1), text, len);
|
||||
}
|
||||
|
||||
if (size >= 4 && memcmp(text, "�", 4) == 0)
|
||||
return 3;
|
||||
if (size >= 4 && memcmp(text, "�", 4) == 0)
|
||||
return 3;
|
||||
|
||||
hoedown_buffer_putc(ob, '&');
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, '&');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts "..." to ellipsis */
|
||||
static size_t
|
||||
smartypants_cb__period(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (size >= 3 && text[1] == '.' && text[2] == '.') {
|
||||
HOEDOWN_BUFPUTSL(ob, "…");
|
||||
return 2;
|
||||
}
|
||||
if (size >= 3 && text[1] == '.' && text[2] == '.') {
|
||||
HOEDOWN_BUFPUTSL(ob, "…");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') {
|
||||
HOEDOWN_BUFPUTSL(ob, "…");
|
||||
return 4;
|
||||
}
|
||||
if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') {
|
||||
HOEDOWN_BUFPUTSL(ob, "…");
|
||||
return 4;
|
||||
}
|
||||
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts `` to opening double quote */
|
||||
static size_t
|
||||
smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (size >= 2 && text[1] == '`') {
|
||||
if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote))
|
||||
return 1;
|
||||
}
|
||||
if (size >= 2 && text[1] == '`') {
|
||||
if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote))
|
||||
return 1;
|
||||
}
|
||||
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts 1/2, 1/4, 3/4 */
|
||||
static size_t
|
||||
smartypants_cb__number(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (word_boundary(previous_char) && size >= 3) {
|
||||
if (text[0] == '1' && text[1] == '/' && text[2] == '2') {
|
||||
if (size == 3 || word_boundary(text[3])) {
|
||||
HOEDOWN_BUFPUTSL(ob, "½");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (word_boundary(previous_char) && size >= 3) {
|
||||
if (text[0] == '1' && text[1] == '/' && text[2] == '2') {
|
||||
if (size == 3 || word_boundary(text[3])) {
|
||||
HOEDOWN_BUFPUTSL(ob, "½");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (text[0] == '1' && text[1] == '/' && text[2] == '4') {
|
||||
if (size == 3 || word_boundary(text[3]) ||
|
||||
(size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) {
|
||||
HOEDOWN_BUFPUTSL(ob, "¼");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (text[0] == '1' && text[1] == '/' && text[2] == '4') {
|
||||
if (size == 3 || word_boundary(text[3]) ||
|
||||
(size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) {
|
||||
HOEDOWN_BUFPUTSL(ob, "¼");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (text[0] == '3' && text[1] == '/' && text[2] == '4') {
|
||||
if (size == 3 || word_boundary(text[3]) ||
|
||||
(size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) {
|
||||
HOEDOWN_BUFPUTSL(ob, "¾");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (text[0] == '3' && text[1] == '/' && text[2] == '4') {
|
||||
if (size == 3 || word_boundary(text[3]) ||
|
||||
(size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) {
|
||||
HOEDOWN_BUFPUTSL(ob, "¾");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
hoedown_buffer_putc(ob, text[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts " to left or right double quote */
|
||||
static size_t
|
||||
smartypants_cb__dquote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote))
|
||||
HOEDOWN_BUFPUTSL(ob, """);
|
||||
if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote))
|
||||
HOEDOWN_BUFPUTSL(ob, """);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
static const char *skip_tags[] = {
|
||||
"pre", "code", "var", "samp", "kbd", "math", "script", "style"
|
||||
};
|
||||
static const size_t skip_tags_count = 8;
|
||||
static const char *skip_tags[] = {
|
||||
"pre", "code", "var", "samp", "kbd", "math", "script", "style"
|
||||
};
|
||||
static const size_t skip_tags_count = 8;
|
||||
|
||||
size_t tag, i = 0;
|
||||
size_t tag, i = 0;
|
||||
|
||||
/* This is a comment. Copy everything verbatim until --> or EOF is seen. */
|
||||
if (i + 4 < size && memcmp(text, "<!--", 4) == 0) {
|
||||
i += 4;
|
||||
while (i + 3 < size && memcmp(text + i, "-->", 3) != 0)
|
||||
i++;
|
||||
i += 3;
|
||||
hoedown_buffer_put(ob, text, i + 1);
|
||||
return i;
|
||||
}
|
||||
/* This is a comment. Copy everything verbatim until --> or EOF is seen. */
|
||||
if (i + 4 < size && memcmp(text, "<!--", 4) == 0) {
|
||||
i += 4;
|
||||
while (i + 3 < size && memcmp(text + i, "-->", 3) != 0)
|
||||
i++;
|
||||
i += 3;
|
||||
hoedown_buffer_put(ob, text, i + 1);
|
||||
return i;
|
||||
}
|
||||
|
||||
while (i < size && text[i] != '>')
|
||||
i++;
|
||||
while (i < size && text[i] != '>')
|
||||
i++;
|
||||
|
||||
for (tag = 0; tag < skip_tags_count; ++tag) {
|
||||
if (hoedown_html_is_tag(text, size, skip_tags[tag]) == HOEDOWN_HTML_TAG_OPEN)
|
||||
break;
|
||||
}
|
||||
for (tag = 0; tag < skip_tags_count; ++tag) {
|
||||
if (hoedown_html_is_tag(text, size, skip_tags[tag]) == HOEDOWN_HTML_TAG_OPEN)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag < skip_tags_count) {
|
||||
for (;;) {
|
||||
while (i < size && text[i] != '<')
|
||||
i++;
|
||||
if (tag < skip_tags_count) {
|
||||
for (;;) {
|
||||
while (i < size && text[i] != '<')
|
||||
i++;
|
||||
|
||||
if (i == size)
|
||||
break;
|
||||
if (i == size)
|
||||
break;
|
||||
|
||||
if (hoedown_html_is_tag(text + i, size - i, skip_tags[tag]) == HOEDOWN_HTML_TAG_CLOSE)
|
||||
break;
|
||||
if (hoedown_html_is_tag(text + i, size - i, skip_tags[tag]) == HOEDOWN_HTML_TAG_CLOSE)
|
||||
break;
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
while (i < size && text[i] != '>')
|
||||
i++;
|
||||
}
|
||||
while (i < size && text[i] != '>')
|
||||
i++;
|
||||
}
|
||||
|
||||
hoedown_buffer_put(ob, text, i + 1);
|
||||
return i;
|
||||
hoedown_buffer_put(ob, text, i + 1);
|
||||
return i;
|
||||
}
|
||||
|
||||
static size_t
|
||||
smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
||||
{
|
||||
if (size < 2)
|
||||
return 0;
|
||||
if (size < 2)
|
||||
return 0;
|
||||
|
||||
switch (text[1]) {
|
||||
case '\\':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '.':
|
||||
case '-':
|
||||
case '`':
|
||||
hoedown_buffer_putc(ob, text[1]);
|
||||
return 1;
|
||||
switch (text[1]) {
|
||||
case '\\':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '.':
|
||||
case '-':
|
||||
case '`':
|
||||
hoedown_buffer_putc(ob, text[1]);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
hoedown_buffer_putc(ob, '\\');
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
hoedown_buffer_putc(ob, '\\');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -408,28 +408,28 @@ static struct {
|
||||
void
|
||||
hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *text, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
struct smartypants_data smrt = {0, 0};
|
||||
size_t i;
|
||||
struct smartypants_data smrt = {0, 0};
|
||||
|
||||
if (!text)
|
||||
return;
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
hoedown_buffer_grow(ob, size);
|
||||
hoedown_buffer_grow(ob, size);
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
size_t org;
|
||||
uint8_t action = 0;
|
||||
for (i = 0; i < size; ++i) {
|
||||
size_t org;
|
||||
uint8_t action = 0;
|
||||
|
||||
org = i;
|
||||
while (i < size && (action = smartypants_cb_chars[text[i]]) == 0)
|
||||
i++;
|
||||
org = i;
|
||||
while (i < size && (action = smartypants_cb_chars[text[i]]) == 0)
|
||||
i++;
|
||||
|
||||
if (i > org)
|
||||
hoedown_buffer_put(ob, text + org, i - org);
|
||||
if (i > org)
|
||||
hoedown_buffer_put(ob, text + org, i - org);
|
||||
|
||||
if (i < size) {
|
||||
i += smartypants_cb_ptrs[(int)action]
|
||||
(ob, &smrt, i ? text[i - 1] : 0, text + i, size - i);
|
||||
}
|
||||
}
|
||||
if (i < size) {
|
||||
i += smartypants_cb_ptrs[(int)action]
|
||||
(ob, &smrt, i ? text[i - 1] : 0, text + i, size - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,71 +9,71 @@
|
||||
void
|
||||
hoedown_stack_init(hoedown_stack *st, size_t initial_size)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
st->item = NULL;
|
||||
st->size = st->asize = 0;
|
||||
st->item = NULL;
|
||||
st->size = st->asize = 0;
|
||||
|
||||
if (!initial_size)
|
||||
initial_size = 8;
|
||||
if (!initial_size)
|
||||
initial_size = 8;
|
||||
|
||||
hoedown_stack_grow(st, initial_size);
|
||||
hoedown_stack_grow(st, initial_size);
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_stack_uninit(hoedown_stack *st)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
free(st->item);
|
||||
free(st->item);
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_stack_grow(hoedown_stack *st, size_t neosz)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
if (st->asize >= neosz)
|
||||
return;
|
||||
if (st->asize >= neosz)
|
||||
return;
|
||||
|
||||
st->item = hoedown_realloc(st->item, neosz * sizeof(void *));
|
||||
memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *));
|
||||
st->item = hoedown_realloc(st->item, neosz * sizeof(void *));
|
||||
memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *));
|
||||
|
||||
st->asize = neosz;
|
||||
st->asize = neosz;
|
||||
|
||||
if (st->size > neosz)
|
||||
st->size = neosz;
|
||||
if (st->size > neosz)
|
||||
st->size = neosz;
|
||||
}
|
||||
|
||||
void
|
||||
hoedown_stack_push(hoedown_stack *st, void *item)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
if (st->size >= st->asize)
|
||||
hoedown_stack_grow(st, st->size * 2);
|
||||
if (st->size >= st->asize)
|
||||
hoedown_stack_grow(st, st->size * 2);
|
||||
|
||||
st->item[st->size++] = item;
|
||||
st->item[st->size++] = item;
|
||||
}
|
||||
|
||||
void *
|
||||
hoedown_stack_pop(hoedown_stack *st)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
if (!st->size)
|
||||
return NULL;
|
||||
if (!st->size)
|
||||
return NULL;
|
||||
|
||||
return st->item[--st->size];
|
||||
return st->item[--st->size];
|
||||
}
|
||||
|
||||
void *
|
||||
hoedown_stack_top(const hoedown_stack *st)
|
||||
{
|
||||
assert(st);
|
||||
assert(st);
|
||||
|
||||
if (!st->size)
|
||||
return NULL;
|
||||
if (!st->size)
|
||||
return NULL;
|
||||
|
||||
return st->item[st->size - 1];
|
||||
return st->item[st->size - 1];
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
void
|
||||
hoedown_version(int *major, int *minor, int *revision)
|
||||
{
|
||||
*major = HOEDOWN_VERSION_MAJOR;
|
||||
*minor = HOEDOWN_VERSION_MINOR;
|
||||
*revision = HOEDOWN_VERSION_REVISION;
|
||||
*major = HOEDOWN_VERSION_MAJOR;
|
||||
*minor = HOEDOWN_VERSION_MINOR;
|
||||
*revision = HOEDOWN_VERSION_REVISION;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ generate_export_header(MultiMC_iconfix)
|
||||
|
||||
# Install it
|
||||
install(
|
||||
TARGETS MultiMC_iconfix
|
||||
RUNTIME DESTINATION ${LIBRARY_DEST_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR}
|
||||
TARGETS MultiMC_iconfix
|
||||
RUNTIME DESTINATION ${LIBRARY_DEST_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR}
|
||||
)
|
@ -61,40 +61,40 @@
|
||||
// internal helper. Converts an integer value to an unique string token
|
||||
template <typename T> struct HexString
|
||||
{
|
||||
inline HexString(const T t) : val(t)
|
||||
{
|
||||
}
|
||||
inline HexString(const T t) : val(t)
|
||||
{
|
||||
}
|
||||
|
||||
inline void write(QChar *&dest) const
|
||||
{
|
||||
const ushort hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
const char *c = reinterpret_cast<const char *>(&val);
|
||||
for (uint i = 0; i < sizeof(T); ++i)
|
||||
{
|
||||
*dest++ = hexChars[*c & 0xf];
|
||||
*dest++ = hexChars[(*c & 0xf0) >> 4];
|
||||
++c;
|
||||
}
|
||||
}
|
||||
const T val;
|
||||
inline void write(QChar *&dest) const
|
||||
{
|
||||
const ushort hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
const char *c = reinterpret_cast<const char *>(&val);
|
||||
for (uint i = 0; i < sizeof(T); ++i)
|
||||
{
|
||||
*dest++ = hexChars[*c & 0xf];
|
||||
*dest++ = hexChars[(*c & 0xf0) >> 4];
|
||||
++c;
|
||||
}
|
||||
}
|
||||
const T val;
|
||||
};
|
||||
|
||||
// specialization to enable fast concatenating of our string tokens to a string
|
||||
template <typename T> struct QConcatenable<HexString<T>>
|
||||
{
|
||||
typedef HexString<T> type;
|
||||
enum
|
||||
{
|
||||
ExactSize = true
|
||||
};
|
||||
static int size(const HexString<T> &)
|
||||
{
|
||||
return sizeof(T) * 2;
|
||||
}
|
||||
static inline void appendTo(const HexString<T> &str, QChar *&out)
|
||||
{
|
||||
str.write(out);
|
||||
}
|
||||
typedef QString ConvertTo;
|
||||
typedef HexString<T> type;
|
||||
enum
|
||||
{
|
||||
ExactSize = true
|
||||
};
|
||||
static int size(const HexString<T> &)
|
||||
{
|
||||
return sizeof(T) * 2;
|
||||
}
|
||||
static inline void appendTo(const HexString<T> &str, QChar *&out)
|
||||
{
|
||||
str.write(out);
|
||||
}
|
||||
typedef QString ConvertTo;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -61,46 +61,46 @@ class QIconLoader;
|
||||
|
||||
struct QIconDirInfo
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
Fixed,
|
||||
Scalable,
|
||||
Threshold
|
||||
};
|
||||
QIconDirInfo(const QString &_path = QString())
|
||||
: path(_path), size(0), maxSize(0), minSize(0), threshold(0), type(Threshold)
|
||||
{
|
||||
}
|
||||
QString path;
|
||||
short size;
|
||||
short maxSize;
|
||||
short minSize;
|
||||
short threshold;
|
||||
Type type : 4;
|
||||
enum Type
|
||||
{
|
||||
Fixed,
|
||||
Scalable,
|
||||
Threshold
|
||||
};
|
||||
QIconDirInfo(const QString &_path = QString())
|
||||
: path(_path), size(0), maxSize(0), minSize(0), threshold(0), type(Threshold)
|
||||
{
|
||||
}
|
||||
QString path;
|
||||
short size;
|
||||
short maxSize;
|
||||
short minSize;
|
||||
short threshold;
|
||||
Type type : 4;
|
||||
};
|
||||
|
||||
class QIconLoaderEngineEntry
|
||||
{
|
||||
public:
|
||||
virtual ~QIconLoaderEngineEntry()
|
||||
{
|
||||
}
|
||||
virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) = 0;
|
||||
QString filename;
|
||||
QIconDirInfo dir;
|
||||
static int count;
|
||||
virtual ~QIconLoaderEngineEntry()
|
||||
{
|
||||
}
|
||||
virtual QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) = 0;
|
||||
QString filename;
|
||||
QIconDirInfo dir;
|
||||
static int count;
|
||||
};
|
||||
|
||||
struct ScalableEntry : public QIconLoaderEngineEntry
|
||||
{
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
|
||||
QIcon svgIcon;
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
|
||||
QIcon svgIcon;
|
||||
};
|
||||
|
||||
struct PixmapEntry : public QIconLoaderEngineEntry
|
||||
{
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
|
||||
QPixmap basePixmap;
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE;
|
||||
QPixmap basePixmap;
|
||||
};
|
||||
|
||||
typedef QList<QIconLoaderEngineEntry *> QThemeIconEntries;
|
||||
@ -109,107 +109,107 @@ typedef QList<QIconLoaderEngineEntry *> QThemeIconEntries;
|
||||
class QIconLoaderEngineFixed : public QIconEngine
|
||||
{
|
||||
public:
|
||||
QIconLoaderEngineFixed(const QString &iconName = QString());
|
||||
~QIconLoaderEngineFixed();
|
||||
QIconLoaderEngineFixed(const QString &iconName = QString());
|
||||
~QIconLoaderEngineFixed();
|
||||
|
||||
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
|
||||
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
|
||||
QIconEngine *clone() const;
|
||||
bool read(QDataStream &in);
|
||||
bool write(QDataStream &out) const;
|
||||
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state);
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state);
|
||||
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state);
|
||||
QIconEngine *clone() const;
|
||||
bool read(QDataStream &in);
|
||||
bool write(QDataStream &out) const;
|
||||
|
||||
private:
|
||||
QString key() const;
|
||||
bool hasIcon() const;
|
||||
void ensureLoaded();
|
||||
void virtual_hook(int id, void *data);
|
||||
QIconLoaderEngineEntry *entryForSize(const QSize &size);
|
||||
QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other);
|
||||
QThemeIconEntries m_entries;
|
||||
QString m_iconName;
|
||||
uint m_key;
|
||||
QString key() const;
|
||||
bool hasIcon() const;
|
||||
void ensureLoaded();
|
||||
void virtual_hook(int id, void *data);
|
||||
QIconLoaderEngineEntry *entryForSize(const QSize &size);
|
||||
QIconLoaderEngineFixed(const QIconLoaderEngineFixed &other);
|
||||
QThemeIconEntries m_entries;
|
||||
QString m_iconName;
|
||||
uint m_key;
|
||||
|
||||
friend class QIconLoader;
|
||||
friend class QIconLoader;
|
||||
};
|
||||
|
||||
class QIconTheme
|
||||
{
|
||||
public:
|
||||
QIconTheme(const QString &name);
|
||||
QIconTheme() : m_valid(false)
|
||||
{
|
||||
}
|
||||
QStringList parents()
|
||||
{
|
||||
return m_parents;
|
||||
}
|
||||
QVector<QIconDirInfo> keyList()
|
||||
{
|
||||
return m_keyList;
|
||||
}
|
||||
QString contentDir()
|
||||
{
|
||||
return m_contentDir;
|
||||
}
|
||||
QStringList contentDirs()
|
||||
{
|
||||
return m_contentDirs;
|
||||
}
|
||||
bool isValid()
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
QIconTheme(const QString &name);
|
||||
QIconTheme() : m_valid(false)
|
||||
{
|
||||
}
|
||||
QStringList parents()
|
||||
{
|
||||
return m_parents;
|
||||
}
|
||||
QVector<QIconDirInfo> keyList()
|
||||
{
|
||||
return m_keyList;
|
||||
}
|
||||
QString contentDir()
|
||||
{
|
||||
return m_contentDir;
|
||||
}
|
||||
QStringList contentDirs()
|
||||
{
|
||||
return m_contentDirs;
|
||||
}
|
||||
bool isValid()
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
QString m_contentDir;
|
||||
QStringList m_contentDirs;
|
||||
QVector<QIconDirInfo> m_keyList;
|
||||
QStringList m_parents;
|
||||
bool m_valid;
|
||||
QString m_contentDir;
|
||||
QStringList m_contentDirs;
|
||||
QVector<QIconDirInfo> m_keyList;
|
||||
QStringList m_parents;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
class QIconLoader
|
||||
{
|
||||
public:
|
||||
QIconLoader();
|
||||
QThemeIconEntries loadIcon(const QString &iconName) const;
|
||||
uint themeKey() const
|
||||
{
|
||||
return m_themeKey;
|
||||
}
|
||||
QIconLoader();
|
||||
QThemeIconEntries loadIcon(const QString &iconName) const;
|
||||
uint themeKey() const
|
||||
{
|
||||
return m_themeKey;
|
||||
}
|
||||
|
||||
QString themeName() const
|
||||
{
|
||||
return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme;
|
||||
}
|
||||
void setThemeName(const QString &themeName);
|
||||
QIconTheme theme()
|
||||
{
|
||||
return themeList.value(themeName());
|
||||
}
|
||||
void setThemeSearchPath(const QStringList &searchPaths);
|
||||
QStringList themeSearchPaths() const;
|
||||
QIconDirInfo dirInfo(int dirindex);
|
||||
static QIconLoader *instance();
|
||||
void updateSystemTheme();
|
||||
void invalidateKey()
|
||||
{
|
||||
m_themeKey++;
|
||||
}
|
||||
void ensureInitialized();
|
||||
QString themeName() const
|
||||
{
|
||||
return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme;
|
||||
}
|
||||
void setThemeName(const QString &themeName);
|
||||
QIconTheme theme()
|
||||
{
|
||||
return themeList.value(themeName());
|
||||
}
|
||||
void setThemeSearchPath(const QStringList &searchPaths);
|
||||
QStringList themeSearchPaths() const;
|
||||
QIconDirInfo dirInfo(int dirindex);
|
||||
static QIconLoader *instance();
|
||||
void updateSystemTheme();
|
||||
void invalidateKey()
|
||||
{
|
||||
m_themeKey++;
|
||||
}
|
||||
void ensureInitialized();
|
||||
|
||||
private:
|
||||
QThemeIconEntries findIconHelper(const QString &themeName, const QString &iconName,
|
||||
QStringList &visited) const;
|
||||
uint m_themeKey;
|
||||
bool m_supportsSvg;
|
||||
bool m_initialized;
|
||||
QThemeIconEntries findIconHelper(const QString &themeName, const QString &iconName,
|
||||
QStringList &visited) const;
|
||||
uint m_themeKey;
|
||||
bool m_supportsSvg;
|
||||
bool m_initialized;
|
||||
|
||||
mutable QString m_userTheme;
|
||||
mutable QString m_systemTheme;
|
||||
mutable QStringList m_iconDirs;
|
||||
mutable QHash<QString, QIconTheme> themeList;
|
||||
mutable QString m_userTheme;
|
||||
mutable QString m_systemTheme;
|
||||
mutable QStringList m_iconDirs;
|
||||
mutable QHash<QString, QIconTheme> themeList;
|
||||
};
|
||||
|
||||
} // QtXdg
|
||||
|
@ -46,17 +46,17 @@ namespace
|
||||
{
|
||||
struct QtIconCache : public IconCache
|
||||
{
|
||||
QtIconCache()
|
||||
{
|
||||
qAddPostRoutine(qt_cleanup_icon_cache);
|
||||
}
|
||||
QtIconCache()
|
||||
{
|
||||
qAddPostRoutine(qt_cleanup_icon_cache);
|
||||
}
|
||||
};
|
||||
}
|
||||
Q_GLOBAL_STATIC(IconCache, qtIconCache)
|
||||
|
||||
static void qt_cleanup_icon_cache()
|
||||
{
|
||||
qtIconCache()->clear();
|
||||
qtIconCache()->clear();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
@ -78,7 +78,7 @@ XdgIcon::~XdgIcon()
|
||||
************************************************/
|
||||
QString XdgIcon::themeName()
|
||||
{
|
||||
return QIcon::themeName();
|
||||
return QIcon::themeName();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
@ -86,8 +86,8 @@ QString XdgIcon::themeName()
|
||||
************************************************/
|
||||
void XdgIcon::setThemeName(const QString &themeName)
|
||||
{
|
||||
QIcon::setThemeName(themeName);
|
||||
QtXdg::QIconLoader::instance()->updateSystemTheme();
|
||||
QIcon::setThemeName(themeName);
|
||||
QtXdg::QIconLoader::instance()->updateSystemTheme();
|
||||
}
|
||||
|
||||
/************************************************
|
||||
@ -96,43 +96,43 @@ void XdgIcon::setThemeName(const QString &themeName)
|
||||
************************************************/
|
||||
QIcon XdgIcon::fromTheme(const QString &iconName, const QIcon &fallback)
|
||||
{
|
||||
if (iconName.isEmpty())
|
||||
return fallback;
|
||||
if (iconName.isEmpty())
|
||||
return fallback;
|
||||
|
||||
bool isAbsolute = (iconName[0] == '/');
|
||||
bool isAbsolute = (iconName[0] == '/');
|
||||
|
||||
QString name = QFileInfo(iconName).fileName();
|
||||
if (name.endsWith(".png", Qt::CaseInsensitive) ||
|
||||
name.endsWith(".svg", Qt::CaseInsensitive) ||
|
||||
name.endsWith(".xpm", Qt::CaseInsensitive))
|
||||
{
|
||||
name.truncate(name.length() - 4);
|
||||
}
|
||||
QString name = QFileInfo(iconName).fileName();
|
||||
if (name.endsWith(".png", Qt::CaseInsensitive) ||
|
||||
name.endsWith(".svg", Qt::CaseInsensitive) ||
|
||||
name.endsWith(".xpm", Qt::CaseInsensitive))
|
||||
{
|
||||
name.truncate(name.length() - 4);
|
||||
}
|
||||
|
||||
QIcon icon;
|
||||
QIcon icon;
|
||||
|
||||
if (qtIconCache()->contains(name))
|
||||
{
|
||||
icon = *qtIconCache()->object(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
QIcon *cachedIcon;
|
||||
if (!isAbsolute)
|
||||
cachedIcon = new QIcon(new QtXdg::QIconLoaderEngineFixed(name));
|
||||
else
|
||||
cachedIcon = new QIcon(iconName);
|
||||
qtIconCache()->insert(name, cachedIcon);
|
||||
icon = *cachedIcon;
|
||||
}
|
||||
if (qtIconCache()->contains(name))
|
||||
{
|
||||
icon = *qtIconCache()->object(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
QIcon *cachedIcon;
|
||||
if (!isAbsolute)
|
||||
cachedIcon = new QIcon(new QtXdg::QIconLoaderEngineFixed(name));
|
||||
else
|
||||
cachedIcon = new QIcon(iconName);
|
||||
qtIconCache()->insert(name, cachedIcon);
|
||||
icon = *cachedIcon;
|
||||
}
|
||||
|
||||
// Note the qapp check is to allow lazy loading of static icons
|
||||
// Supporting fallbacks will not work for this case.
|
||||
if (qApp && !isAbsolute && icon.availableSizes().isEmpty())
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
return icon;
|
||||
// Note the qapp check is to allow lazy loading of static icons
|
||||
// Supporting fallbacks will not work for this case.
|
||||
if (qApp && !isAbsolute && icon.availableSizes().isEmpty())
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
@ -141,12 +141,12 @@ QIcon XdgIcon::fromTheme(const QString &iconName, const QIcon &fallback)
|
||||
************************************************/
|
||||
QIcon XdgIcon::fromTheme(const QStringList &iconNames, const QIcon &fallback)
|
||||
{
|
||||
foreach (QString iconName, iconNames)
|
||||
{
|
||||
QIcon icon = fromTheme(iconName);
|
||||
if (!icon.isNull())
|
||||
return icon;
|
||||
}
|
||||
foreach (QString iconName, iconNames)
|
||||
{
|
||||
QIcon icon = fromTheme(iconName);
|
||||
if (!icon.isNull())
|
||||
return icon;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
return fallback;
|
||||
}
|
||||
|
@ -36,13 +36,13 @@
|
||||
class MULTIMC_ICONFIX_EXPORT XdgIcon
|
||||
{
|
||||
public:
|
||||
static QIcon fromTheme(const QString &iconName, const QIcon &fallback = QIcon());
|
||||
static QIcon fromTheme(const QStringList &iconNames, const QIcon &fallback = QIcon());
|
||||
static QIcon fromTheme(const QString &iconName, const QIcon &fallback = QIcon());
|
||||
static QIcon fromTheme(const QStringList &iconNames, const QIcon &fallback = QIcon());
|
||||
|
||||
static QString themeName();
|
||||
static void setThemeName(const QString &themeName);
|
||||
static QString themeName();
|
||||
static void setThemeName(const QString &themeName);
|
||||
|
||||
protected:
|
||||
explicit XdgIcon();
|
||||
virtual ~XdgIcon();
|
||||
explicit XdgIcon();
|
||||
virtual ~XdgIcon();
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ set(CMAKE_JAVA_JAR_ENTRY_POINT JavaCheck)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
|
||||
|
||||
set(SRC
|
||||
JavaCheck.java
|
||||
JavaCheck.java
|
||||
)
|
||||
|
||||
add_jar(JavaCheck ${SRC})
|
||||
|
@ -2,23 +2,23 @@ import java.lang.Integer;
|
||||
|
||||
public class JavaCheck
|
||||
{
|
||||
private static final String[] keys = {"os.arch", "java.version"};
|
||||
public static void main (String [] args)
|
||||
{
|
||||
int ret = 0;
|
||||
for(String key : keys)
|
||||
{
|
||||
String property = System.getProperty(key);
|
||||
if(property != null)
|
||||
{
|
||||
System.out.println(key + "=" + property);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(ret);
|
||||
}
|
||||
private static final String[] keys = {"os.arch", "java.version"};
|
||||
public static void main (String [] args)
|
||||
{
|
||||
int ret = 0;
|
||||
for(String key : keys)
|
||||
{
|
||||
String property = System.getProperty(key);
|
||||
if(property != null)
|
||||
{
|
||||
System.out.println(key + "=" + property);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(ret);
|
||||
}
|
||||
}
|
||||
|
@ -7,15 +7,15 @@ set(CMAKE_JAVA_JAR_ENTRY_POINT org.multimc.EntryPoint)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS -target 1.6 -source 1.6 -Xlint:deprecation -Xlint:unchecked)
|
||||
|
||||
set(SRC
|
||||
org/multimc/EntryPoint.java
|
||||
org/multimc/Launcher.java
|
||||
org/multimc/LegacyFrame.java
|
||||
org/multimc/NotFoundException.java
|
||||
org/multimc/ParamBucket.java
|
||||
org/multimc/ParseException.java
|
||||
org/multimc/Utils.java
|
||||
org/multimc/onesix/OneSixLauncher.java
|
||||
net/minecraft/Launcher.java
|
||||
org/multimc/EntryPoint.java
|
||||
org/multimc/Launcher.java
|
||||
org/multimc/LegacyFrame.java
|
||||
org/multimc/NotFoundException.java
|
||||
org/multimc/ParamBucket.java
|
||||
org/multimc/ParseException.java
|
||||
org/multimc/Utils.java
|
||||
org/multimc/onesix/OneSixLauncher.java
|
||||
net/minecraft/Launcher.java
|
||||
)
|
||||
add_jar(NewLaunch ${SRC})
|
||||
install_jar(NewLaunch "${JARS_DEST_DIR}")
|
||||
|
@ -28,138 +28,138 @@ import java.net.MalformedURLException;
|
||||
|
||||
public class Launcher extends Applet implements AppletStub
|
||||
{
|
||||
private Applet wrappedApplet;
|
||||
private URL documentBase;
|
||||
private boolean active = false;
|
||||
private final Map<String, String> params;
|
||||
private Applet wrappedApplet;
|
||||
private URL documentBase;
|
||||
private boolean active = false;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public Launcher(Applet applet, URL documentBase)
|
||||
{
|
||||
params = new TreeMap<String, String>();
|
||||
public Launcher(Applet applet, URL documentBase)
|
||||
{
|
||||
params = new TreeMap<String, String>();
|
||||
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
this.wrappedApplet = applet;
|
||||
this.documentBase = documentBase;
|
||||
}
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
this.wrappedApplet = applet;
|
||||
this.documentBase = documentBase;
|
||||
}
|
||||
|
||||
public void setParameter(String name, String value)
|
||||
{
|
||||
params.put(name, value);
|
||||
}
|
||||
public void setParameter(String name, String value)
|
||||
{
|
||||
params.put(name, value);
|
||||
}
|
||||
|
||||
public void replace(Applet applet)
|
||||
{
|
||||
this.wrappedApplet = applet;
|
||||
public void replace(Applet applet)
|
||||
{
|
||||
this.wrappedApplet = applet;
|
||||
|
||||
applet.setStub(this);
|
||||
applet.setSize(getWidth(), getHeight());
|
||||
applet.setStub(this);
|
||||
applet.setSize(getWidth(), getHeight());
|
||||
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
this.setLayout(new BorderLayout());
|
||||
this.add(applet, "Center");
|
||||
|
||||
applet.init();
|
||||
active = true;
|
||||
applet.start();
|
||||
validate();
|
||||
}
|
||||
applet.init();
|
||||
active = true;
|
||||
applet.start();
|
||||
validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String name)
|
||||
{
|
||||
String param = params.get(name);
|
||||
if (param != null)
|
||||
return param;
|
||||
try
|
||||
{
|
||||
return super.getParameter(name);
|
||||
} catch (Exception ignore){}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getParameter(String name)
|
||||
{
|
||||
String param = params.get(name);
|
||||
if (param != null)
|
||||
return param;
|
||||
try
|
||||
{
|
||||
return super.getParameter(name);
|
||||
} catch (Exception ignore){}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appletResize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
@Override
|
||||
public void appletResize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
@Override
|
||||
public void resize(int width, int height)
|
||||
{
|
||||
wrappedApplet.resize(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(Dimension d)
|
||||
{
|
||||
wrappedApplet.resize(d);
|
||||
}
|
||||
@Override
|
||||
public void resize(Dimension d)
|
||||
{
|
||||
wrappedApplet.resize(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
if (wrappedApplet != null)
|
||||
{
|
||||
wrappedApplet.init();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
if (wrappedApplet != null)
|
||||
{
|
||||
wrappedApplet.init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
wrappedApplet.start();
|
||||
active = true;
|
||||
}
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
wrappedApplet.start();
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
wrappedApplet.stop();
|
||||
active = false;
|
||||
}
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
wrappedApplet.stop();
|
||||
active = false;
|
||||
}
|
||||
|
||||
public void destroy()
|
||||
{
|
||||
wrappedApplet.destroy();
|
||||
}
|
||||
public void destroy()
|
||||
{
|
||||
wrappedApplet.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDocumentBase()
|
||||
{
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public URL getDocumentBase()
|
||||
{
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b)
|
||||
{
|
||||
super.setVisible(b);
|
||||
wrappedApplet.setVisible(b);
|
||||
}
|
||||
public void update(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
public void paint(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void setVisible(boolean b)
|
||||
{
|
||||
super.setVisible(b);
|
||||
wrappedApplet.setVisible(b);
|
||||
}
|
||||
public void update(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
public void paint(Graphics paramGraphics)
|
||||
{
|
||||
}
|
||||
}
|
@ -21,131 +21,131 @@ import java.nio.charset.Charset;
|
||||
|
||||
public class EntryPoint
|
||||
{
|
||||
private enum Action
|
||||
{
|
||||
Proceed,
|
||||
Launch,
|
||||
Abort
|
||||
}
|
||||
private enum Action
|
||||
{
|
||||
Proceed,
|
||||
Launch,
|
||||
Abort
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
EntryPoint listener = new EntryPoint();
|
||||
int retCode = listener.listen();
|
||||
if (retCode != 0)
|
||||
{
|
||||
System.out.println("Exiting with " + retCode);
|
||||
System.exit(retCode);
|
||||
}
|
||||
}
|
||||
public static void main(String[] args)
|
||||
{
|
||||
EntryPoint listener = new EntryPoint();
|
||||
int retCode = listener.listen();
|
||||
if (retCode != 0)
|
||||
{
|
||||
System.out.println("Exiting with " + retCode);
|
||||
System.exit(retCode);
|
||||
}
|
||||
}
|
||||
|
||||
private Action parseLine(String inData) throws ParseException
|
||||
{
|
||||
String[] pair = inData.split(" ", 2);
|
||||
private Action parseLine(String inData) throws ParseException
|
||||
{
|
||||
String[] pair = inData.split(" ", 2);
|
||||
|
||||
if(pair.length == 1)
|
||||
{
|
||||
String command = pair[0];
|
||||
if (pair[0].equals("launch"))
|
||||
return Action.Launch;
|
||||
if(pair.length == 1)
|
||||
{
|
||||
String command = pair[0];
|
||||
if (pair[0].equals("launch"))
|
||||
return Action.Launch;
|
||||
|
||||
else if (pair[0].equals("abort"))
|
||||
return Action.Abort;
|
||||
else if (pair[0].equals("abort"))
|
||||
return Action.Abort;
|
||||
|
||||
else throw new ParseException();
|
||||
}
|
||||
else throw new ParseException();
|
||||
}
|
||||
|
||||
if(pair.length != 2)
|
||||
throw new ParseException();
|
||||
if(pair.length != 2)
|
||||
throw new ParseException();
|
||||
|
||||
String command = pair[0];
|
||||
String param = pair[1];
|
||||
String command = pair[0];
|
||||
String param = pair[1];
|
||||
|
||||
if(command.equals("launcher"))
|
||||
{
|
||||
if(param.equals("onesix"))
|
||||
{
|
||||
m_launcher = new OneSixLauncher();
|
||||
Utils.log("Using onesix launcher.");
|
||||
Utils.log();
|
||||
return Action.Proceed;
|
||||
}
|
||||
else
|
||||
throw new ParseException();
|
||||
}
|
||||
if(command.equals("launcher"))
|
||||
{
|
||||
if(param.equals("onesix"))
|
||||
{
|
||||
m_launcher = new OneSixLauncher();
|
||||
Utils.log("Using onesix launcher.");
|
||||
Utils.log();
|
||||
return Action.Proceed;
|
||||
}
|
||||
else
|
||||
throw new ParseException();
|
||||
}
|
||||
|
||||
m_params.add(command, param);
|
||||
//System.out.println(command + " : " + param);
|
||||
return Action.Proceed;
|
||||
}
|
||||
m_params.add(command, param);
|
||||
//System.out.println(command + " : " + param);
|
||||
return Action.Proceed;
|
||||
}
|
||||
|
||||
public int listen()
|
||||
{
|
||||
BufferedReader buffer;
|
||||
try
|
||||
{
|
||||
buffer = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e)
|
||||
{
|
||||
System.err.println("For some reason, your java does not support UTF-8. Consider living in the current century.");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
boolean isListening = true;
|
||||
boolean isAborted = false;
|
||||
// Main loop
|
||||
while (isListening)
|
||||
{
|
||||
String inData;
|
||||
try
|
||||
{
|
||||
// Read from the pipe one line at a time
|
||||
inData = buffer.readLine();
|
||||
if (inData != null)
|
||||
{
|
||||
Action a = parseLine(inData);
|
||||
if(a == Action.Abort)
|
||||
{
|
||||
isListening = false;
|
||||
isAborted = true;
|
||||
}
|
||||
if(a == Action.Launch)
|
||||
{
|
||||
isListening = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isListening = false;
|
||||
isAborted = true;
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.err.println("Launcher ABORT due to IO exception:");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
System.err.println("Launcher ABORT due to PARSE exception:");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(isAborted)
|
||||
{
|
||||
System.err.println("Launch aborted by MultiMC.");
|
||||
return 1;
|
||||
}
|
||||
if(m_launcher != null)
|
||||
{
|
||||
return m_launcher.launch(m_params);
|
||||
}
|
||||
System.err.println("No valid launcher implementation specified.");
|
||||
return 1;
|
||||
}
|
||||
public int listen()
|
||||
{
|
||||
BufferedReader buffer;
|
||||
try
|
||||
{
|
||||
buffer = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e)
|
||||
{
|
||||
System.err.println("For some reason, your java does not support UTF-8. Consider living in the current century.");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
boolean isListening = true;
|
||||
boolean isAborted = false;
|
||||
// Main loop
|
||||
while (isListening)
|
||||
{
|
||||
String inData;
|
||||
try
|
||||
{
|
||||
// Read from the pipe one line at a time
|
||||
inData = buffer.readLine();
|
||||
if (inData != null)
|
||||
{
|
||||
Action a = parseLine(inData);
|
||||
if(a == Action.Abort)
|
||||
{
|
||||
isListening = false;
|
||||
isAborted = true;
|
||||
}
|
||||
if(a == Action.Launch)
|
||||
{
|
||||
isListening = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isListening = false;
|
||||
isAborted = true;
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
System.err.println("Launcher ABORT due to IO exception:");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
System.err.println("Launcher ABORT due to PARSE exception:");
|
||||
e.printStackTrace();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(isAborted)
|
||||
{
|
||||
System.err.println("Launch aborted by MultiMC.");
|
||||
return 1;
|
||||
}
|
||||
if(m_launcher != null)
|
||||
{
|
||||
return m_launcher.launch(m_params);
|
||||
}
|
||||
System.err.println("No valid launcher implementation specified.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
private ParamBucket m_params = new ParamBucket();
|
||||
private org.multimc.Launcher m_launcher;
|
||||
private ParamBucket m_params = new ParamBucket();
|
||||
private org.multimc.Launcher m_launcher;
|
||||
}
|
||||
|
@ -18,5 +18,5 @@ package org.multimc;
|
||||
|
||||
public interface Launcher
|
||||
{
|
||||
abstract int launch(ParamBucket params);
|
||||
abstract int launch(ParamBucket params);
|
||||
}
|
||||
|
@ -22,65 +22,65 @@ import java.util.List;
|
||||
|
||||
public class ParamBucket
|
||||
{
|
||||
public void add(String key, String value)
|
||||
{
|
||||
List<String> coll = null;
|
||||
if(!m_params.containsKey(key))
|
||||
{
|
||||
coll = new ArrayList<String>();
|
||||
m_params.put(key, coll);
|
||||
}
|
||||
else
|
||||
{
|
||||
coll = m_params.get(key);
|
||||
}
|
||||
coll.add(value);
|
||||
}
|
||||
public void add(String key, String value)
|
||||
{
|
||||
List<String> coll = null;
|
||||
if(!m_params.containsKey(key))
|
||||
{
|
||||
coll = new ArrayList<String>();
|
||||
m_params.put(key, coll);
|
||||
}
|
||||
else
|
||||
{
|
||||
coll = m_params.get(key);
|
||||
}
|
||||
coll.add(value);
|
||||
}
|
||||
|
||||
public List<String> all(String key) throws NotFoundException
|
||||
{
|
||||
if(!m_params.containsKey(key))
|
||||
throw new NotFoundException();
|
||||
return m_params.get(key);
|
||||
}
|
||||
public List<String> all(String key) throws NotFoundException
|
||||
{
|
||||
if(!m_params.containsKey(key))
|
||||
throw new NotFoundException();
|
||||
return m_params.get(key);
|
||||
}
|
||||
|
||||
public List<String> allSafe(String key, List<String> def)
|
||||
{
|
||||
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return m_params.get(key);
|
||||
}
|
||||
public List<String> allSafe(String key, List<String> def)
|
||||
{
|
||||
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return m_params.get(key);
|
||||
}
|
||||
|
||||
public List<String> allSafe(String key)
|
||||
{
|
||||
return allSafe(key, new ArrayList<String>());
|
||||
}
|
||||
public List<String> allSafe(String key)
|
||||
{
|
||||
return allSafe(key, new ArrayList<String>());
|
||||
}
|
||||
|
||||
public String first(String key) throws NotFoundException
|
||||
{
|
||||
List<String> list = all(key);
|
||||
if(list.size() < 1)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return list.get(0);
|
||||
}
|
||||
public String first(String key) throws NotFoundException
|
||||
{
|
||||
List<String> list = all(key);
|
||||
if(list.size() < 1)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
public String firstSafe(String key, String def)
|
||||
{
|
||||
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return m_params.get(key).get(0);
|
||||
}
|
||||
public String firstSafe(String key, String def)
|
||||
{
|
||||
if(!m_params.containsKey(key) || m_params.get(key).size() < 1)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return m_params.get(key).get(0);
|
||||
}
|
||||
|
||||
public String firstSafe(String key)
|
||||
{
|
||||
return firstSafe(key, "");
|
||||
}
|
||||
public String firstSafe(String key)
|
||||
{
|
||||
return firstSafe(key, "");
|
||||
}
|
||||
|
||||
private HashMap<String, List<String>> m_params = new HashMap<String, List<String>>();
|
||||
private HashMap<String, List<String>> m_params = new HashMap<String, List<String>>();
|
||||
}
|
||||
|
@ -34,86 +34,86 @@ import java.util.zip.ZipFile;
|
||||
|
||||
public class Utils
|
||||
{
|
||||
/**
|
||||
* Combine two parts of a path.
|
||||
*
|
||||
* @param path1
|
||||
* @param path2
|
||||
* @return the paths, combined
|
||||
*/
|
||||
public static String combine(String path1, String path2)
|
||||
{
|
||||
File file1 = new File(path1);
|
||||
File file2 = new File(file1, path2);
|
||||
return file2.getPath();
|
||||
}
|
||||
/**
|
||||
* Combine two parts of a path.
|
||||
*
|
||||
* @param path1
|
||||
* @param path2
|
||||
* @return the paths, combined
|
||||
*/
|
||||
public static String combine(String path1, String path2)
|
||||
{
|
||||
File file1 = new File(path1);
|
||||
File file2 = new File(file1, path2);
|
||||
return file2.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a list of strings into a string using a separator!
|
||||
*
|
||||
* @param strings the string list to join
|
||||
* @param separator the glue
|
||||
* @return the result.
|
||||
*/
|
||||
public static String join(List<String> strings, String separator)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String sep = "";
|
||||
for (String s : strings)
|
||||
{
|
||||
sb.append(sep).append(s);
|
||||
sep = separator;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
* Join a list of strings into a string using a separator!
|
||||
*
|
||||
* @param strings the string list to join
|
||||
* @param separator the glue
|
||||
* @return the result.
|
||||
*/
|
||||
public static String join(List<String> strings, String separator)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String sep = "";
|
||||
for (String s : strings)
|
||||
{
|
||||
sb.append(sep).append(s);
|
||||
sep = separator;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a field that looks like a Minecraft base folder in a supplied class
|
||||
*
|
||||
* @param mc the class to scan
|
||||
*/
|
||||
public static Field getMCPathField(Class<?> mc)
|
||||
{
|
||||
Field[] fields = mc.getDeclaredFields();
|
||||
/**
|
||||
* Finds a field that looks like a Minecraft base folder in a supplied class
|
||||
*
|
||||
* @param mc the class to scan
|
||||
*/
|
||||
public static Field getMCPathField(Class<?> mc)
|
||||
{
|
||||
Field[] fields = mc.getDeclaredFields();
|
||||
|
||||
for (Field f : fields)
|
||||
{
|
||||
if (f.getType() != File.class)
|
||||
{
|
||||
// Has to be File
|
||||
continue;
|
||||
}
|
||||
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC))
|
||||
{
|
||||
// And Private Static.
|
||||
continue;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
for (Field f : fields)
|
||||
{
|
||||
if (f.getType() != File.class)
|
||||
{
|
||||
// Has to be File
|
||||
continue;
|
||||
}
|
||||
if (f.getModifiers() != (Modifier.PRIVATE + Modifier.STATIC))
|
||||
{
|
||||
// And Private Static.
|
||||
continue;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log to the MultiMC console
|
||||
*
|
||||
* @param message A String containing the message
|
||||
* @param level A String containing the level name. See MinecraftLauncher::getLevel()
|
||||
*/
|
||||
public static void log(String message, String level)
|
||||
{
|
||||
// Kinda dirty
|
||||
String tag = "!![" + level + "]!";
|
||||
System.out.println(tag + message.replace("\n", "\n" + tag));
|
||||
}
|
||||
/**
|
||||
* Log to the MultiMC console
|
||||
*
|
||||
* @param message A String containing the message
|
||||
* @param level A String containing the level name. See MinecraftLauncher::getLevel()
|
||||
*/
|
||||
public static void log(String message, String level)
|
||||
{
|
||||
// Kinda dirty
|
||||
String tag = "!![" + level + "]!";
|
||||
System.out.println(tag + message.replace("\n", "\n" + tag));
|
||||
}
|
||||
|
||||
public static void log(String message)
|
||||
{
|
||||
log(message, "MultiMC");
|
||||
}
|
||||
public static void log(String message)
|
||||
{
|
||||
log(message, "MultiMC");
|
||||
}
|
||||
|
||||
public static void log()
|
||||
{
|
||||
System.out.println();
|
||||
}
|
||||
public static void log()
|
||||
{
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,208 +27,208 @@ import java.util.List;
|
||||
|
||||
public class OneSixLauncher implements Launcher
|
||||
{
|
||||
// parameters, separated from ParamBucket
|
||||
private List<String> libraries;
|
||||
private List<String> mcparams;
|
||||
private List<String> mods;
|
||||
private List<String> jarmods;
|
||||
private List<String> coremods;
|
||||
private List<String> traits;
|
||||
private String appletClass;
|
||||
private String mainClass;
|
||||
private String nativePath;
|
||||
private String userName, sessionId;
|
||||
private String windowTitle;
|
||||
private String windowParams;
|
||||
// parameters, separated from ParamBucket
|
||||
private List<String> libraries;
|
||||
private List<String> mcparams;
|
||||
private List<String> mods;
|
||||
private List<String> jarmods;
|
||||
private List<String> coremods;
|
||||
private List<String> traits;
|
||||
private String appletClass;
|
||||
private String mainClass;
|
||||
private String nativePath;
|
||||
private String userName, sessionId;
|
||||
private String windowTitle;
|
||||
private String windowParams;
|
||||
|
||||
// secondary parameters
|
||||
private int winSizeW;
|
||||
private int winSizeH;
|
||||
private boolean maximize;
|
||||
private String cwd;
|
||||
// secondary parameters
|
||||
private int winSizeW;
|
||||
private int winSizeH;
|
||||
private boolean maximize;
|
||||
private String cwd;
|
||||
|
||||
// the much abused system classloader, for convenience (for further abuse)
|
||||
private ClassLoader cl;
|
||||
// the much abused system classloader, for convenience (for further abuse)
|
||||
private ClassLoader cl;
|
||||
|
||||
private void processParams(ParamBucket params) throws NotFoundException
|
||||
{
|
||||
libraries = params.all("cp");
|
||||
mcparams = params.allSafe("param", new ArrayList<String>() );
|
||||
mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
|
||||
appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
|
||||
traits = params.allSafe("traits", new ArrayList<String>());
|
||||
nativePath = params.first("natives");
|
||||
private void processParams(ParamBucket params) throws NotFoundException
|
||||
{
|
||||
libraries = params.all("cp");
|
||||
mcparams = params.allSafe("param", new ArrayList<String>() );
|
||||
mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft");
|
||||
appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet");
|
||||
traits = params.allSafe("traits", new ArrayList<String>());
|
||||
nativePath = params.first("natives");
|
||||
|
||||
userName = params.first("userName");
|
||||
sessionId = params.first("sessionId");
|
||||
windowTitle = params.firstSafe("windowTitle", "Minecraft");
|
||||
windowParams = params.firstSafe("windowParams", "854x480");
|
||||
userName = params.first("userName");
|
||||
sessionId = params.first("sessionId");
|
||||
windowTitle = params.firstSafe("windowTitle", "Minecraft");
|
||||
windowParams = params.firstSafe("windowParams", "854x480");
|
||||
|
||||
cwd = System.getProperty("user.dir");
|
||||
cwd = System.getProperty("user.dir");
|
||||
|
||||
winSizeW = 854;
|
||||
winSizeH = 480;
|
||||
maximize = false;
|
||||
winSizeW = 854;
|
||||
winSizeH = 480;
|
||||
maximize = false;
|
||||
|
||||
String[] dimStrings = windowParams.split("x");
|
||||
String[] dimStrings = windowParams.split("x");
|
||||
|
||||
if (windowParams.equalsIgnoreCase("max"))
|
||||
{
|
||||
maximize = true;
|
||||
}
|
||||
else if (dimStrings.length == 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
winSizeW = Integer.parseInt(dimStrings[0]);
|
||||
winSizeH = Integer.parseInt(dimStrings[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
}
|
||||
if (windowParams.equalsIgnoreCase("max"))
|
||||
{
|
||||
maximize = true;
|
||||
}
|
||||
else if (dimStrings.length == 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
winSizeW = Integer.parseInt(dimStrings[0]);
|
||||
winSizeH = Integer.parseInt(dimStrings[1]);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
int legacyLaunch()
|
||||
{
|
||||
// Get the Minecraft Class and set the base folder
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
mc = cl.loadClass(mainClass);
|
||||
int legacyLaunch()
|
||||
{
|
||||
// Get the Minecraft Class and set the base folder
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
mc = cl.loadClass(mainClass);
|
||||
|
||||
Field f = Utils.getMCPathField(mc);
|
||||
Field f = Utils.getMCPathField(mc);
|
||||
|
||||
if (f == null)
|
||||
{
|
||||
System.err.println("Could not find Minecraft path field.");
|
||||
}
|
||||
else
|
||||
{
|
||||
f.setAccessible(true);
|
||||
f.set(null, new File(cwd));
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
if (f == null)
|
||||
{
|
||||
System.err.println("Could not find Minecraft path field.");
|
||||
}
|
||||
else
|
||||
{
|
||||
f.setAccessible(true);
|
||||
f.set(null, new File(cwd));
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Could not set base folder. Failed to find/access Minecraft main class:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
System.setProperty("minecraft.applet.TargetDirectory", cwd);
|
||||
System.setProperty("minecraft.applet.TargetDirectory", cwd);
|
||||
|
||||
if(!traits.contains("noapplet"))
|
||||
{
|
||||
Utils.log("Launching with applet wrapper...");
|
||||
try
|
||||
{
|
||||
Class<?> MCAppletClass = cl.loadClass(appletClass);
|
||||
Applet mcappl = (Applet) MCAppletClass.newInstance();
|
||||
LegacyFrame mcWindow = new LegacyFrame(windowTitle);
|
||||
mcWindow.start(mcappl, userName, sessionId, winSizeW, winSizeH, maximize);
|
||||
return 0;
|
||||
} catch (Exception e)
|
||||
{
|
||||
Utils.log("Applet wrapper failed:", "Error");
|
||||
e.printStackTrace(System.err);
|
||||
Utils.log();
|
||||
Utils.log("Falling back to using main class.");
|
||||
}
|
||||
}
|
||||
if(!traits.contains("noapplet"))
|
||||
{
|
||||
Utils.log("Launching with applet wrapper...");
|
||||
try
|
||||
{
|
||||
Class<?> MCAppletClass = cl.loadClass(appletClass);
|
||||
Applet mcappl = (Applet) MCAppletClass.newInstance();
|
||||
LegacyFrame mcWindow = new LegacyFrame(windowTitle);
|
||||
mcWindow.start(mcappl, userName, sessionId, winSizeW, winSizeH, maximize);
|
||||
return 0;
|
||||
} catch (Exception e)
|
||||
{
|
||||
Utils.log("Applet wrapper failed:", "Error");
|
||||
e.printStackTrace(System.err);
|
||||
Utils.log();
|
||||
Utils.log("Falling back to using main class.");
|
||||
}
|
||||
}
|
||||
|
||||
// init params for the main method to chomp on.
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
|
||||
try
|
||||
{
|
||||
mc.getMethod("main", String[].class).invoke(null, (Object) paramsArray);
|
||||
return 0;
|
||||
} catch (Exception e)
|
||||
{
|
||||
Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// init params for the main method to chomp on.
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
|
||||
try
|
||||
{
|
||||
mc.getMethod("main", String[].class).invoke(null, (Object) paramsArray);
|
||||
return 0;
|
||||
} catch (Exception e)
|
||||
{
|
||||
Utils.log("Failed to invoke the Minecraft main class:", "Fatal");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int launchWithMainClass()
|
||||
{
|
||||
// window size, title and state, onesix
|
||||
if (maximize)
|
||||
{
|
||||
// FIXME: there is no good way to maximize the minecraft window in onesix.
|
||||
// the following often breaks linux screen setups
|
||||
// mcparams.add("--fullscreen");
|
||||
}
|
||||
else
|
||||
{
|
||||
mcparams.add("--width");
|
||||
mcparams.add(Integer.toString(winSizeW));
|
||||
mcparams.add("--height");
|
||||
mcparams.add(Integer.toString(winSizeH));
|
||||
}
|
||||
int launchWithMainClass()
|
||||
{
|
||||
// window size, title and state, onesix
|
||||
if (maximize)
|
||||
{
|
||||
// FIXME: there is no good way to maximize the minecraft window in onesix.
|
||||
// the following often breaks linux screen setups
|
||||
// mcparams.add("--fullscreen");
|
||||
}
|
||||
else
|
||||
{
|
||||
mcparams.add("--width");
|
||||
mcparams.add(Integer.toString(winSizeW));
|
||||
mcparams.add("--height");
|
||||
mcparams.add(Integer.toString(winSizeH));
|
||||
}
|
||||
|
||||
// Get the Minecraft Class.
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
mc = cl.loadClass(mainClass);
|
||||
} catch (ClassNotFoundException e)
|
||||
{
|
||||
System.err.println("Failed to find Minecraft main class:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
// Get the Minecraft Class.
|
||||
Class<?> mc;
|
||||
try
|
||||
{
|
||||
mc = cl.loadClass(mainClass);
|
||||
} catch (ClassNotFoundException e)
|
||||
{
|
||||
System.err.println("Failed to find Minecraft main class:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the main method.
|
||||
Method meth;
|
||||
try
|
||||
{
|
||||
meth = mc.getMethod("main", String[].class);
|
||||
} catch (NoSuchMethodException e)
|
||||
{
|
||||
System.err.println("Failed to acquire the main method:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
// get the main method.
|
||||
Method meth;
|
||||
try
|
||||
{
|
||||
meth = mc.getMethod("main", String[].class);
|
||||
} catch (NoSuchMethodException e)
|
||||
{
|
||||
System.err.println("Failed to acquire the main method:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// init params for the main method to chomp on.
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
|
||||
try
|
||||
{
|
||||
// static method doesn't have an instance
|
||||
meth.invoke(null, (Object) paramsArray);
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to start Minecraft:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// init params for the main method to chomp on.
|
||||
String[] paramsArray = mcparams.toArray(new String[mcparams.size()]);
|
||||
try
|
||||
{
|
||||
// static method doesn't have an instance
|
||||
meth.invoke(null, (Object) paramsArray);
|
||||
} catch (Exception e)
|
||||
{
|
||||
System.err.println("Failed to start Minecraft:");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int launch(ParamBucket params)
|
||||
{
|
||||
// get and process the launch script params
|
||||
try
|
||||
{
|
||||
processParams(params);
|
||||
} catch (NotFoundException e)
|
||||
{
|
||||
System.err.println("Not enough arguments.");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
public int launch(ParamBucket params)
|
||||
{
|
||||
// get and process the launch script params
|
||||
try
|
||||
{
|
||||
processParams(params);
|
||||
} catch (NotFoundException e)
|
||||
{
|
||||
System.err.println("Not enough arguments.");
|
||||
e.printStackTrace(System.err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// grab the system classloader and ...
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
// grab the system classloader and ...
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
|
||||
if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
|
||||
{
|
||||
// legacy launch uses the applet wrapper
|
||||
return legacyLaunch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal launch just calls main()
|
||||
return launchWithMainClass();
|
||||
}
|
||||
}
|
||||
if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch") )
|
||||
{
|
||||
// legacy launch uses the applet wrapper
|
||||
return legacyLaunch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal launch just calls main()
|
||||
return launchWithMainClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,22 +8,22 @@ option(PACK200_BUILD_BINARY "Build a tiny utility that decompresses pack200 stre
|
||||
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
|
||||
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)
|
||||
@ -39,12 +39,12 @@ generate_export_header(MultiMC_unpack200)
|
||||
|
||||
# Install it
|
||||
install(
|
||||
TARGETS MultiMC_unpack200
|
||||
RUNTIME DESTINATION ${LIBRARY_DEST_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR}
|
||||
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)
|
||||
add_executable(anti200 anti200.cpp)
|
||||
target_link_libraries(anti200 MultiMC_unpack200)
|
||||
endif()
|
||||
|
@ -8,36 +8,36 @@
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
@ -47,188 +47,188 @@
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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();
|
||||
rewind();
|
||||
}
|
||||
|
||||
void band::setIndex(cpindex *ix_)
|
||||
{
|
||||
assert(ix_ == nullptr || ixTag == ix_->ixTag);
|
||||
ix = ix_;
|
||||
assert(ix_ == nullptr || ixTag == ix_->ixTag);
|
||||
ix = ix_;
|
||||
}
|
||||
void band::setIndexByTag(byte tag)
|
||||
{
|
||||
setIndex(u->cp.getIndex(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;
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
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)
|
||||
@ -240,184 +240,184 @@ int band::getIntCount(int tag)
|
||||
|
||||
struct band_init
|
||||
{
|
||||
int defc;
|
||||
int index;
|
||||
int defc;
|
||||
int index;
|
||||
};
|
||||
|
||||
#define BAND_INIT(name, cspec, ix) \
|
||||
{ \
|
||||
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_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;
|
||||
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));
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,138 +30,138 @@ 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
|
||||
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)
|
||||
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
|
||||
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)
|
||||
// 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];
|
||||
}
|
||||
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 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 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);
|
||||
void setIndex(cpindex *ix_);
|
||||
void setIndexByTag(byte tag);
|
||||
|
||||
// Parse the band and its meta-coding header.
|
||||
void readData(int expectedLength = 0);
|
||||
// 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]);
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
int getIntTotal();
|
||||
int getIntCount(int tag);
|
||||
|
||||
static band *makeBands(unpacker *u);
|
||||
static void initIndexes(unpacker *u);
|
||||
static band *makeBands(unpacker *u);
|
||||
static void initIndexes(unpacker *u);
|
||||
};
|
||||
|
||||
extern band all_bands[];
|
||||
@ -173,179 +173,179 @@ extern band all_bands[];
|
||||
// Band schema:
|
||||
enum band_number
|
||||
{
|
||||
// e_archive_magic,
|
||||
// e_archive_header,
|
||||
// e_band_headers,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// _self_linker_op family
|
||||
e_bc_thisfield,
|
||||
e_bc_superfield,
|
||||
e_bc_thismethod,
|
||||
e_bc_supermethod,
|
||||
|
||||
// bc_invokeinit family:
|
||||
e_bc_initref,
|
||||
// bc_invokeinit family:
|
||||
e_bc_initref,
|
||||
|
||||
// bytecode escape sequences
|
||||
e_bc_escref,
|
||||
e_bc_escrefsize,
|
||||
e_bc_escsize,
|
||||
e_bc_escbyte,
|
||||
// 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
|
||||
// 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:
|
||||
|
@ -36,182 +36,182 @@ static byte dummy[1 << 10];
|
||||
|
||||
bool bytes::inBounds(const void *p)
|
||||
{
|
||||
return p >= ptr && p < limit();
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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;
|
||||
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 *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;
|
||||
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;
|
||||
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_);
|
||||
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_);
|
||||
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;
|
||||
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
|
||||
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;
|
||||
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 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;
|
||||
int len = length();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (get(i) == x)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -27,225 +27,225 @@
|
||||
|
||||
struct bytes
|
||||
{
|
||||
int8_t *ptr;
|
||||
size_t len;
|
||||
int8_t *limit()
|
||||
{
|
||||
return ptr + len;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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
|
||||
}
|
||||
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));
|
||||
}
|
||||
// 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
|
||||
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.
|
||||
@ -253,34 +253,34 @@ struct ptrlist : fillbytes
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -35,9 +35,9 @@ struct unpacker;
|
||||
#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 \
|
||||
}
|
||||
{ \
|
||||
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
|
||||
@ -45,126 +45,126 @@ struct unpacker;
|
||||
|
||||
struct coding
|
||||
{
|
||||
int spec; // B,H,S,D
|
||||
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;
|
||||
// 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();
|
||||
}
|
||||
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 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);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
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 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);
|
||||
}
|
||||
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
|
||||
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
|
||||
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
|
||||
// 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)
|
||||
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
|
||||
B_MAX = 5,
|
||||
C_SLOP = B_MAX * 10
|
||||
};
|
||||
|
||||
struct coding_method;
|
||||
@ -172,76 +172,76 @@ 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
|
||||
// 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 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));
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
// 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();
|
||||
// Used only for asserts.
|
||||
bool hasValue();
|
||||
|
||||
void done()
|
||||
{
|
||||
assert(!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();
|
||||
// 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)
|
||||
value_stream vs0; // initial state snapshot (vs.meta==this)
|
||||
|
||||
coding_method *next; // what to do when we run out of bytes
|
||||
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
|
||||
// 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;
|
||||
// pointer to outer unpacker, for error checks etc.
|
||||
unpacker *u;
|
||||
|
||||
// Initialize a value stream.
|
||||
void reset(value_stream *state);
|
||||
// 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);
|
||||
// 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);
|
||||
};
|
||||
|
@ -55,388 +55,388 @@
|
||||
|
||||
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,
|
||||
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)*/
|
||||
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)*/
|
||||
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)*/
|
||||
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)*/
|
||||
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)*/
|
||||
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)*/
|
||||
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)*/
|
||||
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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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)*/
|
||||
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
|
||||
// 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
|
||||
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
|
||||
// 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
|
||||
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
|
||||
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
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -35,104 +35,104 @@ struct value_stream;
|
||||
|
||||
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
|
||||
};
|
||||
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);
|
||||
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_;
|
||||
}
|
||||
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
|
||||
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];
|
||||
// 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);
|
||||
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);
|
||||
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
|
||||
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);
|
||||
entry **hashTab;
|
||||
uint32_t hashTabLength;
|
||||
entry *&hashTabRef(byte tag, bytes &b);
|
||||
entry *ensureUtf8(bytes &b);
|
||||
entry *ensureClass(bytes &b);
|
||||
|
||||
// Well-known Utf8 symbols.
|
||||
enum
|
||||
{
|
||||
// Well-known Utf8 symbols.
|
||||
enum
|
||||
{
|
||||
#define SNAME(n, s) s_##s,
|
||||
ALL_ATTR_DO(SNAME)
|
||||
ALL_ATTR_DO(SNAME)
|
||||
#undef SNAME
|
||||
s_lt_init_gt, // <init>
|
||||
s_LIMIT
|
||||
};
|
||||
entry *sym[s_LIMIT];
|
||||
s_lt_init_gt, // <init>
|
||||
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]);
|
||||
// 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;
|
||||
// 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
|
||||
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 expandSignatures();
|
||||
void initMemberIndexes();
|
||||
|
||||
void computeOutputOrder();
|
||||
void computeOutputIndexes();
|
||||
void resetOutputIndexes();
|
||||
void computeOutputOrder();
|
||||
void computeOutputIndexes();
|
||||
void resetOutputIndexes();
|
||||
};
|
||||
|
||||
/*
|
||||
@ -141,407 +141,407 @@ struct constant_pool
|
||||
*/
|
||||
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);
|
||||
}
|
||||
};
|
||||
// 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
|
||||
// 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;
|
||||
// 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
|
||||
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;
|
||||
// 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;
|
||||
// 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
|
||||
typedef int64_t (*read_input_fn_t)(unpacker *self, void *buf, int64_t minlen,
|
||||
int64_t maxlen);
|
||||
read_input_fn_t read_input_fn;
|
||||
// callback to read at least one byte, up to available input
|
||||
typedef int64_t (*read_input_fn_t)(unpacker *self, void *buf, int64_t minlen,
|
||||
int64_t maxlen);
|
||||
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
|
||||
// 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
|
||||
// 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 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?
|
||||
// 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;
|
||||
// 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)
|
||||
// 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)
|
||||
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();
|
||||
}
|
||||
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);
|
||||
// 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);
|
||||
// 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
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
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];
|
||||
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();
|
||||
}
|
||||
// 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);
|
||||
// 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();
|
||||
}
|
||||
// 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();
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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();
|
||||
// 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);
|
||||
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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
};
|
||||
|
@ -45,118 +45,118 @@
|
||||
// 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;
|
||||
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;
|
||||
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
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
// 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;
|
||||
// the input doesn't
|
||||
u.infileptr = input;
|
||||
|
||||
// read the magic!
|
||||
char peek[4];
|
||||
int magic;
|
||||
magic = read_magic(&u, peek, (int)sizeof(peek));
|
||||
// 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));
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
// 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
|
||||
}
|
||||
// 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);
|
||||
// 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);
|
||||
}
|
||||
|
@ -50,22 +50,22 @@
|
||||
|
||||
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;
|
||||
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);
|
||||
if (msg == nullptr)
|
||||
msg = "corrupt pack file or internal error";
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
@ -35,17 +35,17 @@ void *must_malloc(size_t size);
|
||||
|
||||
inline size_t scale_size(size_t size, size_t scale)
|
||||
{
|
||||
return (size > PSIZE_MAX / scale) ? OVERFLOW : size * 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;
|
||||
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);
|
||||
return add_size(add_size(size1, size2), size3);
|
||||
}
|
||||
|
||||
struct unpacker;
|
||||
|
@ -52,7 +52,7 @@
|
||||
|
||||
inline uint32_t jar::get_crc32(uint32_t c, uchar *ptr, uint32_t len)
|
||||
{
|
||||
return crc32(c, ptr, len);
|
||||
return crc32(c, ptr, len);
|
||||
}
|
||||
|
||||
// FIXME: this is bullshit. Do real endianness detection.
|
||||
@ -68,175 +68,175 @@ inline uint32_t jar::get_crc32(uint32_t c, uchar *ptr, uint32_t len)
|
||||
|
||||
void jar::init(unpacker *u_)
|
||||
{
|
||||
BYTES_OF(*this).clear();
|
||||
u = u_;
|
||||
u->jarout = this;
|
||||
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;
|
||||
}
|
||||
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 crc)
|
||||
{
|
||||
uint32_t fname_length = (uint32_t)strlen(fname);
|
||||
ushort header[23];
|
||||
if (modtime == 0)
|
||||
modtime = default_modtime;
|
||||
uint32_t dostime = get_dostime(modtime);
|
||||
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);
|
||||
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);
|
||||
// required version
|
||||
header[3] = (ushort)SWAP_BYTES(0xA);
|
||||
|
||||
// flags 02 = maximum sub-compression flag
|
||||
header[4] = (store) ? 0x0 : SWAP_BYTES(0x2);
|
||||
// flags 02 = maximum sub-compression flag
|
||||
header[4] = (store) ? 0x0 : SWAP_BYTES(0x2);
|
||||
|
||||
// Compression method 8=deflate.
|
||||
header[5] = (store) ? 0x0 : SWAP_BYTES(0x08);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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 whole thing into the central directory.
|
||||
central_directory.append(header, sizeof(header));
|
||||
|
||||
// Copy the fname to the header.
|
||||
central_directory.append(fname, fname_length);
|
||||
// Copy the fname to the header.
|
||||
central_directory.append(fname, fname_length);
|
||||
|
||||
central_directory_count++;
|
||||
central_directory_count++;
|
||||
}
|
||||
|
||||
void jar::write_jar_header(const char *fname, bool store, int modtime, int len, int clen,
|
||||
uint32_t crc)
|
||||
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);
|
||||
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);
|
||||
// ZIP LOC magic.
|
||||
header[0] = (ushort)SWAP_BYTES(0x4B50);
|
||||
header[1] = (ushort)SWAP_BYTES(0x0403);
|
||||
|
||||
// Version
|
||||
header[2] = (ushort)SWAP_BYTES(0xA);
|
||||
// Version
|
||||
header[2] = (ushort)SWAP_BYTES(0xA);
|
||||
|
||||
// flags 02 = maximum sub-compression flag
|
||||
header[3] = (store) ? 0x0 : SWAP_BYTES(0x2);
|
||||
// flags 02 = maximum sub-compression flag
|
||||
header[3] = (store) ? 0x0 : SWAP_BYTES(0x2);
|
||||
|
||||
// Compression method = deflate
|
||||
header[4] = (store) ? 0x0 : SWAP_BYTES(0x08);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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);
|
||||
// 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;
|
||||
// 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));
|
||||
// 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);
|
||||
// Copy the fname to the header.
|
||||
write_data((char *)fname, (int)fname_length);
|
||||
}
|
||||
|
||||
void jar::write_central_directory()
|
||||
{
|
||||
bytes mc;
|
||||
mc.set("PACK200");
|
||||
bytes mc;
|
||||
mc.set("PACK200");
|
||||
|
||||
ushort header[11];
|
||||
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);
|
||||
// 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 central directory.
|
||||
write_data(central_directory.b);
|
||||
|
||||
// Write the End of Central Directory structure.
|
||||
write_data(header, (int)sizeof(header));
|
||||
// Write the End of Central Directory structure.
|
||||
write_data(header, (int)sizeof(header));
|
||||
|
||||
// Write the comment.
|
||||
write_data(mc);
|
||||
// Write the comment.
|
||||
write_data(mc);
|
||||
}
|
||||
|
||||
// Public API
|
||||
@ -244,74 +244,74 @@ void jar::write_central_directory()
|
||||
// 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
|
||||
}
|
||||
}
|
||||
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)
|
||||
bytes &tail)
|
||||
{
|
||||
int len = (int)(head.len + tail.len);
|
||||
int clen = 0;
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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();
|
||||
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
|
||||
@ -320,9 +320,9 @@ void jar::closeJarFile(bool central)
|
||||
*/
|
||||
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);
|
||||
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
|
||||
@ -336,20 +336,20 @@ extern "C" struct tm *gmtime_r(const time_t *, struct tm *);
|
||||
*/
|
||||
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;
|
||||
// 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
|
||||
@ -358,232 +358,232 @@ uint32_t jar::get_dostime(int modtime)
|
||||
*/
|
||||
bool jar::deflate_bytes(bytes &head, bytes &tail)
|
||||
{
|
||||
int len = (int)(head.len + tail.len);
|
||||
int len = (int)(head.len + tail.len);
|
||||
|
||||
z_stream zs;
|
||||
BYTES_OF(zs).clear();
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
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();
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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);
|
||||
unpacker::read_input_fn_t read_gzin_fn = (unpacker::read_input_fn_t)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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
unpacker::read_input_fn_t read_gzin_fn = (unpacker::read_input_fn_t)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;
|
||||
// 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 = (void *)u->read_input_fn;
|
||||
zstream = NEW(z_stream, 1);
|
||||
u->gzin = this;
|
||||
u->read_input_fn = read_input_via_gzip;
|
||||
BYTES_OF(*this).clear();
|
||||
u = u_;
|
||||
assert(u->gzin == nullptr); // once only, please
|
||||
read_input_fn = (void *)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));
|
||||
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");
|
||||
}
|
||||
// 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 = (unpacker::read_input_fn_t) this->read_input_fn;
|
||||
inflateEnd((z_stream *)zstream);
|
||||
::free(zstream);
|
||||
zstream = nullptr;
|
||||
::free(this);
|
||||
assert(u->gzin == this);
|
||||
u->gzin = nullptr;
|
||||
u->read_input_fn = (unpacker::read_input_fn_t) 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 = ((unpacker::read_input_fn_t)read_input_fn)(u, buf, buflen, buflen);
|
||||
if ((size_t)nr != buflen)
|
||||
unpack_abort("short stream header");
|
||||
int64_t nr = ((unpacker::read_input_fn_t)read_input_fn)(u, buf, buflen, buflen);
|
||||
if ((size_t)nr != buflen)
|
||||
unpack_abort("short stream header");
|
||||
}
|
||||
|
@ -31,80 +31,80 @@ struct unpacker;
|
||||
|
||||
struct jar
|
||||
{
|
||||
// JAR file writer
|
||||
FILE *jarfp;
|
||||
int default_modtime;
|
||||
// JAR file writer
|
||||
FILE *jarfp;
|
||||
int default_modtime;
|
||||
|
||||
// Used by unix2dostime:
|
||||
int modtime_cache;
|
||||
uint32_t dostime_cache;
|
||||
// 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
|
||||
// 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;
|
||||
// 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);
|
||||
// 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 init(unpacker *u_);
|
||||
|
||||
void free()
|
||||
{
|
||||
central_directory.free();
|
||||
deflated.free();
|
||||
}
|
||||
void free()
|
||||
{
|
||||
central_directory.free();
|
||||
deflated.free();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
free();
|
||||
init(u);
|
||||
}
|
||||
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);
|
||||
// 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);
|
||||
// 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
|
||||
// optional gzip input stream control block
|
||||
|
||||
// pointer to outer unpacker, for error checks etc.
|
||||
unpacker *u;
|
||||
// pointer to outer unpacker, for error checks etc.
|
||||
unpacker *u;
|
||||
|
||||
void *read_input_fn; // underlying \bchar\b stream
|
||||
void *zstream; // inflater state
|
||||
char inbuf[1 << 14]; // input buffer
|
||||
void *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 init(unpacker *u_); // pushes new value on u->read_input_fn
|
||||
|
||||
void free();
|
||||
void free();
|
||||
|
||||
void start(int magic);
|
||||
void start(int magic);
|
||||
|
||||
// private stuff
|
||||
void read_fixed_field(char *buf, size_t buflen);
|
||||
// private stuff
|
||||
void read_fixed_field(char *buf, size_t buflen);
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ target_link_libraries(MultiMC_rainbow Qt5::Core Qt5::Gui)
|
||||
|
||||
# Install it
|
||||
install(
|
||||
TARGETS MultiMC_rainbow
|
||||
RUNTIME DESTINATION ${LIBRARY_DEST_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR}
|
||||
TARGETS MultiMC_rainbow
|
||||
RUNTIME DESTINATION ${LIBRARY_DEST_DIR}
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR}
|
||||
)
|
||||
|
@ -50,7 +50,7 @@ RAINBOW_EXPORT qreal luma(const QColor &);
|
||||
* @since 5.0
|
||||
*/
|
||||
RAINBOW_EXPORT void getHcy(const QColor &, qreal *hue, qreal *chroma, qreal *luma,
|
||||
qreal *alpha = 0);
|
||||
qreal *alpha = 0);
|
||||
|
||||
/**
|
||||
* Calculate the contrast ratio between two colors, according to the
|
||||
@ -132,7 +132,7 @@ RAINBOW_EXPORT QColor tint(const QColor &base, const QColor &color, qreal amount
|
||||
/**
|
||||
* Blend two colors into a new color by linear combination.
|
||||
* @code
|
||||
QColor lighter = Rainbow::mix(myColor, Qt::white)
|
||||
QColor lighter = Rainbow::mix(myColor, Qt::white)
|
||||
* @endcode
|
||||
* @param c1 first color.
|
||||
* @param c2 second color.
|
||||
@ -146,9 +146,9 @@ RAINBOW_EXPORT QColor mix(const QColor &c1, const QColor &c2, qreal bias = 0.5);
|
||||
* Blend two colors into a new color by painting the second color over the
|
||||
* first using the specified composition mode.
|
||||
* @code
|
||||
QColor white(Qt::white);
|
||||
white.setAlphaF(0.5);
|
||||
QColor lighter = Rainbow::overlayColors(myColor, white);
|
||||
QColor white(Qt::white);
|
||||
white.setAlphaF(0.5);
|
||||
QColor lighter = Rainbow::overlayColors(myColor, white);
|
||||
@endcode
|
||||
* @param base the base color (alpha channel is ignored).
|
||||
* @param paint the color to be overlayed onto the base color.
|
||||
@ -156,5 +156,5 @@ RAINBOW_EXPORT QColor mix(const QColor &c1, const QColor &c2, qreal bias = 0.5);
|
||||
*/
|
||||
RAINBOW_EXPORT QColor
|
||||
overlayColors(const QColor &base, const QColor &paint,
|
||||
QPainter::CompositionMode comp = QPainter::CompositionMode_SourceOver);
|
||||
QPainter::CompositionMode comp = QPainter::CompositionMode_SourceOver);
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#ifdef RAINBOW_STATIC
|
||||
#define RAINBOW_EXPORT
|
||||
#define RAINBOW_EXPORT
|
||||
#else
|
||||
#ifdef RAINBOW_LIBRARY
|
||||
#define RAINBOW_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define RAINBOW_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#ifdef RAINBOW_LIBRARY
|
||||
#define RAINBOW_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define RAINBOW_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
@ -33,8 +33,8 @@
|
||||
|
||||
static inline qreal wrap(qreal a, qreal d = 1.0)
|
||||
{
|
||||
qreal r = fmod(a, d);
|
||||
return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
|
||||
qreal r = fmod(a, d);
|
||||
return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
|
||||
}
|
||||
|
||||
// normalize: like qBound(a, 0.0, 1.0) but without needing the args and with
|
||||
@ -60,306 +60,306 @@ static const qreal yc[3] = {0.34375, 0.5, 0.15625};
|
||||
class KHCY
|
||||
{
|
||||
public:
|
||||
explicit KHCY(const QColor &color)
|
||||
{
|
||||
qreal r = gamma(color.redF());
|
||||
qreal g = gamma(color.greenF());
|
||||
qreal b = gamma(color.blueF());
|
||||
a = color.alphaF();
|
||||
explicit KHCY(const QColor &color)
|
||||
{
|
||||
qreal r = gamma(color.redF());
|
||||
qreal g = gamma(color.greenF());
|
||||
qreal b = gamma(color.blueF());
|
||||
a = color.alphaF();
|
||||
|
||||
// luma component
|
||||
y = lumag(r, g, b);
|
||||
// luma component
|
||||
y = lumag(r, g, b);
|
||||
|
||||
// hue component
|
||||
qreal p = qMax(qMax(r, g), b);
|
||||
qreal n = qMin(qMin(r, g), b);
|
||||
qreal d = 6.0 * (p - n);
|
||||
if (n == p)
|
||||
{
|
||||
h = 0.0;
|
||||
}
|
||||
else if (r == p)
|
||||
{
|
||||
h = ((g - b) / d);
|
||||
}
|
||||
else if (g == p)
|
||||
{
|
||||
h = ((b - r) / d) + (1.0 / 3.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
h = ((r - g) / d) + (2.0 / 3.0);
|
||||
}
|
||||
// hue component
|
||||
qreal p = qMax(qMax(r, g), b);
|
||||
qreal n = qMin(qMin(r, g), b);
|
||||
qreal d = 6.0 * (p - n);
|
||||
if (n == p)
|
||||
{
|
||||
h = 0.0;
|
||||
}
|
||||
else if (r == p)
|
||||
{
|
||||
h = ((g - b) / d);
|
||||
}
|
||||
else if (g == p)
|
||||
{
|
||||
h = ((b - r) / d) + (1.0 / 3.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
h = ((r - g) / d) + (2.0 / 3.0);
|
||||
}
|
||||
|
||||
// chroma component
|
||||
if (r == g && g == b)
|
||||
{
|
||||
c = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = qMax((y - n) / y, (p - y) / (1 - y));
|
||||
}
|
||||
}
|
||||
explicit KHCY(qreal h_, qreal c_, qreal y_, qreal a_ = 1.0)
|
||||
{
|
||||
h = h_;
|
||||
c = c_;
|
||||
y = y_;
|
||||
a = a_;
|
||||
}
|
||||
// chroma component
|
||||
if (r == g && g == b)
|
||||
{
|
||||
c = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = qMax((y - n) / y, (p - y) / (1 - y));
|
||||
}
|
||||
}
|
||||
explicit KHCY(qreal h_, qreal c_, qreal y_, qreal a_ = 1.0)
|
||||
{
|
||||
h = h_;
|
||||
c = c_;
|
||||
y = y_;
|
||||
a = a_;
|
||||
}
|
||||
|
||||
QColor qColor() const
|
||||
{
|
||||
// start with sane component values
|
||||
qreal _h = wrap(h);
|
||||
qreal _c = normalize(c);
|
||||
qreal _y = normalize(y);
|
||||
QColor qColor() const
|
||||
{
|
||||
// start with sane component values
|
||||
qreal _h = wrap(h);
|
||||
qreal _c = normalize(c);
|
||||
qreal _y = normalize(y);
|
||||
|
||||
// calculate some needed variables
|
||||
qreal _hs = _h * 6.0, th, tm;
|
||||
if (_hs < 1.0)
|
||||
{
|
||||
th = _hs;
|
||||
tm = yc[0] + yc[1] * th;
|
||||
}
|
||||
else if (_hs < 2.0)
|
||||
{
|
||||
th = 2.0 - _hs;
|
||||
tm = yc[1] + yc[0] * th;
|
||||
}
|
||||
else if (_hs < 3.0)
|
||||
{
|
||||
th = _hs - 2.0;
|
||||
tm = yc[1] + yc[2] * th;
|
||||
}
|
||||
else if (_hs < 4.0)
|
||||
{
|
||||
th = 4.0 - _hs;
|
||||
tm = yc[2] + yc[1] * th;
|
||||
}
|
||||
else if (_hs < 5.0)
|
||||
{
|
||||
th = _hs - 4.0;
|
||||
tm = yc[2] + yc[0] * th;
|
||||
}
|
||||
else
|
||||
{
|
||||
th = 6.0 - _hs;
|
||||
tm = yc[0] + yc[2] * th;
|
||||
}
|
||||
// calculate some needed variables
|
||||
qreal _hs = _h * 6.0, th, tm;
|
||||
if (_hs < 1.0)
|
||||
{
|
||||
th = _hs;
|
||||
tm = yc[0] + yc[1] * th;
|
||||
}
|
||||
else if (_hs < 2.0)
|
||||
{
|
||||
th = 2.0 - _hs;
|
||||
tm = yc[1] + yc[0] * th;
|
||||
}
|
||||
else if (_hs < 3.0)
|
||||
{
|
||||
th = _hs - 2.0;
|
||||
tm = yc[1] + yc[2] * th;
|
||||
}
|
||||
else if (_hs < 4.0)
|
||||
{
|
||||
th = 4.0 - _hs;
|
||||
tm = yc[2] + yc[1] * th;
|
||||
}
|
||||
else if (_hs < 5.0)
|
||||
{
|
||||
th = _hs - 4.0;
|
||||
tm = yc[2] + yc[0] * th;
|
||||
}
|
||||
else
|
||||
{
|
||||
th = 6.0 - _hs;
|
||||
tm = yc[0] + yc[2] * th;
|
||||
}
|
||||
|
||||
// calculate RGB channels in sorted order
|
||||
qreal tn, to, tp;
|
||||
if (tm >= _y)
|
||||
{
|
||||
tp = _y + _y * _c * (1.0 - tm) / tm;
|
||||
to = _y + _y * _c * (th - tm) / tm;
|
||||
tn = _y - (_y * _c);
|
||||
}
|
||||
else
|
||||
{
|
||||
tp = _y + (1.0 - _y) * _c;
|
||||
to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
|
||||
tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
|
||||
}
|
||||
// calculate RGB channels in sorted order
|
||||
qreal tn, to, tp;
|
||||
if (tm >= _y)
|
||||
{
|
||||
tp = _y + _y * _c * (1.0 - tm) / tm;
|
||||
to = _y + _y * _c * (th - tm) / tm;
|
||||
tn = _y - (_y * _c);
|
||||
}
|
||||
else
|
||||
{
|
||||
tp = _y + (1.0 - _y) * _c;
|
||||
to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
|
||||
tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
|
||||
}
|
||||
|
||||
// return RGB channels in appropriate order
|
||||
if (_hs < 1.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tp), igamma(to), igamma(tn), a);
|
||||
}
|
||||
else if (_hs < 2.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(to), igamma(tp), igamma(tn), a);
|
||||
}
|
||||
else if (_hs < 3.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tn), igamma(tp), igamma(to), a);
|
||||
}
|
||||
else if (_hs < 4.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tn), igamma(to), igamma(tp), a);
|
||||
}
|
||||
else if (_hs < 5.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(to), igamma(tn), igamma(tp), a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tp), igamma(tn), igamma(to), a);
|
||||
}
|
||||
}
|
||||
// return RGB channels in appropriate order
|
||||
if (_hs < 1.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tp), igamma(to), igamma(tn), a);
|
||||
}
|
||||
else if (_hs < 2.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(to), igamma(tp), igamma(tn), a);
|
||||
}
|
||||
else if (_hs < 3.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tn), igamma(tp), igamma(to), a);
|
||||
}
|
||||
else if (_hs < 4.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tn), igamma(to), igamma(tp), a);
|
||||
}
|
||||
else if (_hs < 5.0)
|
||||
{
|
||||
return QColor::fromRgbF(igamma(to), igamma(tn), igamma(tp), a);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QColor::fromRgbF(igamma(tp), igamma(tn), igamma(to), a);
|
||||
}
|
||||
}
|
||||
|
||||
qreal h, c, y, a;
|
||||
static qreal luma(const QColor &color)
|
||||
{
|
||||
return lumag(gamma(color.redF()), gamma(color.greenF()), gamma(color.blueF()));
|
||||
}
|
||||
qreal h, c, y, a;
|
||||
static qreal luma(const QColor &color)
|
||||
{
|
||||
return lumag(gamma(color.redF()), gamma(color.greenF()), gamma(color.blueF()));
|
||||
}
|
||||
|
||||
private:
|
||||
static qreal gamma(qreal n)
|
||||
{
|
||||
return pow(normalize(n), 2.2);
|
||||
}
|
||||
static qreal igamma(qreal n)
|
||||
{
|
||||
return pow(normalize(n), 1.0 / 2.2);
|
||||
}
|
||||
static qreal lumag(qreal r, qreal g, qreal b)
|
||||
{
|
||||
return r * yc[0] + g * yc[1] + b * yc[2];
|
||||
}
|
||||
static qreal gamma(qreal n)
|
||||
{
|
||||
return pow(normalize(n), 2.2);
|
||||
}
|
||||
static qreal igamma(qreal n)
|
||||
{
|
||||
return pow(normalize(n), 1.0 / 2.2);
|
||||
}
|
||||
static qreal lumag(qreal r, qreal g, qreal b)
|
||||
{
|
||||
return r * yc[0] + g * yc[1] + b * yc[2];
|
||||
}
|
||||
};
|
||||
|
||||
static inline qreal mixQreal(qreal a, qreal b, qreal bias)
|
||||
{
|
||||
return a + (b - a) * bias;
|
||||
return a + (b - a) * bias;
|
||||
}
|
||||
//END internal helper functions
|
||||
|
||||
qreal Rainbow::luma(const QColor &color)
|
||||
{
|
||||
return KHCY::luma(color);
|
||||
return KHCY::luma(color);
|
||||
}
|
||||
|
||||
void Rainbow::getHcy(const QColor &color, qreal *h, qreal *c, qreal *y, qreal *a)
|
||||
{
|
||||
if (!c || !h || !y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
KHCY khcy(color);
|
||||
*c = khcy.c;
|
||||
*h = khcy.h;
|
||||
*y = khcy.y;
|
||||
if (a)
|
||||
{
|
||||
*a = khcy.a;
|
||||
}
|
||||
if (!c || !h || !y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
KHCY khcy(color);
|
||||
*c = khcy.c;
|
||||
*h = khcy.h;
|
||||
*y = khcy.y;
|
||||
if (a)
|
||||
{
|
||||
*a = khcy.a;
|
||||
}
|
||||
}
|
||||
|
||||
static qreal contrastRatioForLuma(qreal y1, qreal y2)
|
||||
{
|
||||
if (y1 > y2)
|
||||
{
|
||||
return (y1 + 0.05) / (y2 + 0.05);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (y2 + 0.05) / (y1 + 0.05);
|
||||
}
|
||||
if (y1 > y2)
|
||||
{
|
||||
return (y1 + 0.05) / (y2 + 0.05);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (y2 + 0.05) / (y1 + 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
qreal Rainbow::contrastRatio(const QColor &c1, const QColor &c2)
|
||||
{
|
||||
return contrastRatioForLuma(luma(c1), luma(c2));
|
||||
return contrastRatioForLuma(luma(c1), luma(c2));
|
||||
}
|
||||
|
||||
QColor Rainbow::lighten(const QColor &color, qreal ky, qreal kc)
|
||||
{
|
||||
KHCY c(color);
|
||||
c.y = 1.0 - normalize((1.0 - c.y) * (1.0 - ky));
|
||||
c.c = 1.0 - normalize((1.0 - c.c) * kc);
|
||||
return c.qColor();
|
||||
KHCY c(color);
|
||||
c.y = 1.0 - normalize((1.0 - c.y) * (1.0 - ky));
|
||||
c.c = 1.0 - normalize((1.0 - c.c) * kc);
|
||||
return c.qColor();
|
||||
}
|
||||
|
||||
QColor Rainbow::darken(const QColor &color, qreal ky, qreal kc)
|
||||
{
|
||||
KHCY c(color);
|
||||
c.y = normalize(c.y * (1.0 - ky));
|
||||
c.c = normalize(c.c * kc);
|
||||
return c.qColor();
|
||||
KHCY c(color);
|
||||
c.y = normalize(c.y * (1.0 - ky));
|
||||
c.c = normalize(c.c * kc);
|
||||
return c.qColor();
|
||||
}
|
||||
|
||||
QColor Rainbow::shade(const QColor &color, qreal ky, qreal kc)
|
||||
{
|
||||
KHCY c(color);
|
||||
c.y = normalize(c.y + ky);
|
||||
c.c = normalize(c.c + kc);
|
||||
return c.qColor();
|
||||
KHCY c(color);
|
||||
c.y = normalize(c.y + ky);
|
||||
c.c = normalize(c.c + kc);
|
||||
return c.qColor();
|
||||
}
|
||||
|
||||
static QColor tintHelper(const QColor &base, qreal baseLuma, const QColor &color, qreal amount)
|
||||
{
|
||||
KHCY result(Rainbow::mix(base, color, pow(amount, 0.3)));
|
||||
result.y = mixQreal(baseLuma, result.y, amount);
|
||||
KHCY result(Rainbow::mix(base, color, pow(amount, 0.3)));
|
||||
result.y = mixQreal(baseLuma, result.y, amount);
|
||||
|
||||
return result.qColor();
|
||||
return result.qColor();
|
||||
}
|
||||
|
||||
QColor Rainbow::tint(const QColor &base, const QColor &color, qreal amount)
|
||||
{
|
||||
if (amount <= 0.0)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
if (amount >= 1.0)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
if (qIsNaN(amount))
|
||||
{
|
||||
return base;
|
||||
}
|
||||
if (amount <= 0.0)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
if (amount >= 1.0)
|
||||
{
|
||||
return color;
|
||||
}
|
||||
if (qIsNaN(amount))
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
qreal baseLuma = luma(base); // cache value because luma call is expensive
|
||||
double ri = contrastRatioForLuma(baseLuma, luma(color));
|
||||
double rg = 1.0 + ((ri + 1.0) * amount * amount * amount);
|
||||
double u = 1.0, l = 0.0;
|
||||
QColor result;
|
||||
for (int i = 12; i; --i)
|
||||
{
|
||||
double a = 0.5 * (l + u);
|
||||
result = tintHelper(base, baseLuma, color, a);
|
||||
double ra = contrastRatioForLuma(baseLuma, luma(result));
|
||||
if (ra > rg)
|
||||
{
|
||||
u = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = a;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
qreal baseLuma = luma(base); // cache value because luma call is expensive
|
||||
double ri = contrastRatioForLuma(baseLuma, luma(color));
|
||||
double rg = 1.0 + ((ri + 1.0) * amount * amount * amount);
|
||||
double u = 1.0, l = 0.0;
|
||||
QColor result;
|
||||
for (int i = 12; i; --i)
|
||||
{
|
||||
double a = 0.5 * (l + u);
|
||||
result = tintHelper(base, baseLuma, color, a);
|
||||
double ra = contrastRatioForLuma(baseLuma, luma(result));
|
||||
if (ra > rg)
|
||||
{
|
||||
u = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = a;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QColor Rainbow::mix(const QColor &c1, const QColor &c2, qreal bias)
|
||||
{
|
||||
if (bias <= 0.0)
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
if (bias >= 1.0)
|
||||
{
|
||||
return c2;
|
||||
}
|
||||
if (qIsNaN(bias))
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
if (bias <= 0.0)
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
if (bias >= 1.0)
|
||||
{
|
||||
return c2;
|
||||
}
|
||||
if (qIsNaN(bias))
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
|
||||
qreal r = mixQreal(c1.redF(), c2.redF(), bias);
|
||||
qreal g = mixQreal(c1.greenF(), c2.greenF(), bias);
|
||||
qreal b = mixQreal(c1.blueF(), c2.blueF(), bias);
|
||||
qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias);
|
||||
qreal r = mixQreal(c1.redF(), c2.redF(), bias);
|
||||
qreal g = mixQreal(c1.greenF(), c2.greenF(), bias);
|
||||
qreal b = mixQreal(c1.blueF(), c2.blueF(), bias);
|
||||
qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias);
|
||||
|
||||
return QColor::fromRgbF(r, g, b, a);
|
||||
return QColor::fromRgbF(r, g, b, a);
|
||||
}
|
||||
|
||||
QColor Rainbow::overlayColors(const QColor &base, const QColor &paint,
|
||||
QPainter::CompositionMode comp)
|
||||
QPainter::CompositionMode comp)
|
||||
{
|
||||
// This isn't the fastest way, but should be "fast enough".
|
||||
// It's also the only safe way to use QPainter::CompositionMode
|
||||
QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter p(&img);
|
||||
QColor start = base;
|
||||
start.setAlpha(255); // opaque
|
||||
p.fillRect(0, 0, 1, 1, start);
|
||||
p.setCompositionMode(comp);
|
||||
p.fillRect(0, 0, 1, 1, paint);
|
||||
p.end();
|
||||
return img.pixel(0, 0);
|
||||
// This isn't the fastest way, but should be "fast enough".
|
||||
// It's also the only safe way to use QPainter::CompositionMode
|
||||
QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter p(&img);
|
||||
QColor start = base;
|
||||
start.setAlpha(255); // opaque
|
||||
p.fillRect(0, 0, 1, 1, start);
|
||||
p.setCompositionMode(comp);
|
||||
p.fillRect(0, 0, 1, 1, paint);
|
||||
p.end();
|
||||
return img.pixel(0, 0);
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ src/distroutils.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND systeminfo_SOURCES src/sys_win32.cpp)
|
||||
list(APPEND systeminfo_SOURCES src/sys_win32.cpp)
|
||||
elseif (UNIX)
|
||||
if(APPLE)
|
||||
list(APPEND systeminfo_SOURCES src/sys_apple.cpp)
|
||||
else()
|
||||
list(APPEND systeminfo_SOURCES src/sys_unix.cpp)
|
||||
endif()
|
||||
if(APPLE)
|
||||
list(APPEND systeminfo_SOURCES src/sys_apple.cpp)
|
||||
else()
|
||||
list(APPEND systeminfo_SOURCES src/sys_unix.cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(systeminfo STATIC ${systeminfo_SOURCES})
|
||||
@ -24,6 +24,6 @@ target_include_directories(systeminfo PUBLIC include)
|
||||
|
||||
include (UnitTest)
|
||||
add_unit_test(sys
|
||||
SOURCES src/sys_test.cpp
|
||||
LIBS systeminfo
|
||||
SOURCES src/sys_test.cpp
|
||||
LIBS systeminfo
|
||||
)
|
||||
|
@ -4,10 +4,10 @@
|
||||
namespace Sys {
|
||||
struct LsbInfo
|
||||
{
|
||||
QString distributor;
|
||||
QString version;
|
||||
QString description;
|
||||
QString codename;
|
||||
QString distributor;
|
||||
QString version;
|
||||
QString description;
|
||||
QString codename;
|
||||
};
|
||||
|
||||
bool main_lsb_info(LsbInfo & out);
|
||||
|
@ -6,37 +6,37 @@ namespace Sys
|
||||
const uint64_t megabyte = 1024ull * 1024ull;
|
||||
struct KernelInfo
|
||||
{
|
||||
QString kernelName;
|
||||
QString kernelVersion;
|
||||
QString kernelName;
|
||||
QString kernelVersion;
|
||||
};
|
||||
|
||||
KernelInfo getKernelInfo();
|
||||
|
||||
struct DistributionInfo
|
||||
{
|
||||
DistributionInfo operator+(const DistributionInfo& rhs) const
|
||||
{
|
||||
DistributionInfo out;
|
||||
if(!distributionName.isEmpty())
|
||||
{
|
||||
out.distributionName = distributionName;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.distributionName = rhs.distributionName;
|
||||
}
|
||||
if(!distributionVersion.isEmpty())
|
||||
{
|
||||
out.distributionVersion = distributionVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.distributionVersion = rhs.distributionVersion;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
QString distributionName;
|
||||
QString distributionVersion;
|
||||
DistributionInfo operator+(const DistributionInfo& rhs) const
|
||||
{
|
||||
DistributionInfo out;
|
||||
if(!distributionName.isEmpty())
|
||||
{
|
||||
out.distributionName = distributionName;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.distributionName = rhs.distributionName;
|
||||
}
|
||||
if(!distributionVersion.isEmpty())
|
||||
{
|
||||
out.distributionVersion = distributionVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.distributionVersion = rhs.distributionVersion;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
QString distributionName;
|
||||
QString distributionVersion;
|
||||
};
|
||||
|
||||
DistributionInfo getDistributionInfo();
|
||||
|
@ -41,243 +41,243 @@ SOFTWARE.
|
||||
|
||||
Sys::DistributionInfo Sys::read_os_release()
|
||||
{
|
||||
Sys::DistributionInfo out;
|
||||
QStringList files = { "/etc/os-release", "/usr/lib/os-release" };
|
||||
QString name;
|
||||
QString version;
|
||||
for (auto &file: files)
|
||||
{
|
||||
if(!QFile::exists(file))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QSettings settings(file, QSettings::IniFormat);
|
||||
if(settings.contains("ID"))
|
||||
{
|
||||
name = settings.value("ID").toString().toLower();
|
||||
}
|
||||
else if (settings.contains("NAME"))
|
||||
{
|
||||
name = settings.value("NAME").toString().toLower();
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Sys::DistributionInfo out;
|
||||
QStringList files = { "/etc/os-release", "/usr/lib/os-release" };
|
||||
QString name;
|
||||
QString version;
|
||||
for (auto &file: files)
|
||||
{
|
||||
if(!QFile::exists(file))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QSettings settings(file, QSettings::IniFormat);
|
||||
if(settings.contains("ID"))
|
||||
{
|
||||
name = settings.value("ID").toString().toLower();
|
||||
}
|
||||
else if (settings.contains("NAME"))
|
||||
{
|
||||
name = settings.value("NAME").toString().toLower();
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(settings.contains("VERSION_ID"))
|
||||
{
|
||||
version = settings.value("VERSION_ID").toString().toLower();
|
||||
}
|
||||
else if(settings.contains("VERSION"))
|
||||
{
|
||||
version = settings.value("VERSION").toString().toLower();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(name.isEmpty())
|
||||
{
|
||||
return out;
|
||||
}
|
||||
out.distributionName = name;
|
||||
out.distributionVersion = version;
|
||||
return out;
|
||||
if(settings.contains("VERSION_ID"))
|
||||
{
|
||||
version = settings.value("VERSION_ID").toString().toLower();
|
||||
}
|
||||
else if(settings.contains("VERSION"))
|
||||
{
|
||||
version = settings.value("VERSION").toString().toLower();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(name.isEmpty())
|
||||
{
|
||||
return out;
|
||||
}
|
||||
out.distributionName = name;
|
||||
out.distributionVersion = version;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool Sys::main_lsb_info(Sys::LsbInfo & out)
|
||||
{
|
||||
int status=0;
|
||||
QProcess lsbProcess;
|
||||
lsbProcess.start("lsb_release -a");
|
||||
lsbProcess.waitForFinished();
|
||||
status = lsbProcess.exitStatus();
|
||||
QString output = lsbProcess.readAllStandardOutput();
|
||||
qDebug() << output;
|
||||
lsbProcess.close();
|
||||
if(status == 0)
|
||||
{
|
||||
auto lines = output.split('\n');
|
||||
for(auto line:lines)
|
||||
{
|
||||
int index = line.indexOf(':');
|
||||
auto key = line.left(index).trimmed();
|
||||
auto value = line.mid(index + 1).toLower().trimmed();
|
||||
if(key == "Distributor ID")
|
||||
out.distributor = value;
|
||||
else if(key == "Release")
|
||||
out.version = value;
|
||||
else if(key == "Description")
|
||||
out.description = value;
|
||||
else if(key == "Codename")
|
||||
out.codename = value;
|
||||
}
|
||||
return !out.distributor.isEmpty();
|
||||
}
|
||||
return false;
|
||||
int status=0;
|
||||
QProcess lsbProcess;
|
||||
lsbProcess.start("lsb_release -a");
|
||||
lsbProcess.waitForFinished();
|
||||
status = lsbProcess.exitStatus();
|
||||
QString output = lsbProcess.readAllStandardOutput();
|
||||
qDebug() << output;
|
||||
lsbProcess.close();
|
||||
if(status == 0)
|
||||
{
|
||||
auto lines = output.split('\n');
|
||||
for(auto line:lines)
|
||||
{
|
||||
int index = line.indexOf(':');
|
||||
auto key = line.left(index).trimmed();
|
||||
auto value = line.mid(index + 1).toLower().trimmed();
|
||||
if(key == "Distributor ID")
|
||||
out.distributor = value;
|
||||
else if(key == "Release")
|
||||
out.version = value;
|
||||
else if(key == "Description")
|
||||
out.description = value;
|
||||
else if(key == "Codename")
|
||||
out.codename = value;
|
||||
}
|
||||
return !out.distributor.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sys::fallback_lsb_info(Sys::LsbInfo & out)
|
||||
{
|
||||
// running lsb_release failed, try to read the file instead
|
||||
// /etc/lsb-release format, if the file even exists, is non-standard.
|
||||
// Only the `lsb_release` command is specified by LSB. Nonetheless, some
|
||||
// distributions install an /etc/lsb-release as part of the base
|
||||
// distribution, but `lsb_release` remains optional.
|
||||
QString file = "/etc/lsb-release";
|
||||
if (QFile::exists(file))
|
||||
{
|
||||
QSettings settings(file, QSettings::IniFormat);
|
||||
if(settings.contains("DISTRIB_ID"))
|
||||
{
|
||||
out.distributor = settings.value("DISTRIB_ID").toString().toLower();
|
||||
}
|
||||
if(settings.contains("DISTRIB_RELEASE"))
|
||||
{
|
||||
out.version = settings.value("DISTRIB_RELEASE").toString().toLower();
|
||||
}
|
||||
return !out.distributor.isEmpty();
|
||||
}
|
||||
return false;
|
||||
// running lsb_release failed, try to read the file instead
|
||||
// /etc/lsb-release format, if the file even exists, is non-standard.
|
||||
// Only the `lsb_release` command is specified by LSB. Nonetheless, some
|
||||
// distributions install an /etc/lsb-release as part of the base
|
||||
// distribution, but `lsb_release` remains optional.
|
||||
QString file = "/etc/lsb-release";
|
||||
if (QFile::exists(file))
|
||||
{
|
||||
QSettings settings(file, QSettings::IniFormat);
|
||||
if(settings.contains("DISTRIB_ID"))
|
||||
{
|
||||
out.distributor = settings.value("DISTRIB_ID").toString().toLower();
|
||||
}
|
||||
if(settings.contains("DISTRIB_RELEASE"))
|
||||
{
|
||||
out.version = settings.value("DISTRIB_RELEASE").toString().toLower();
|
||||
}
|
||||
return !out.distributor.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sys::lsb_postprocess(Sys::LsbInfo & lsb, Sys::DistributionInfo & out)
|
||||
{
|
||||
QString dist = lsb.distributor;
|
||||
QString vers = lsb.version;
|
||||
if(dist.startsWith("redhatenterprise"))
|
||||
{
|
||||
dist = "rhel";
|
||||
}
|
||||
else if(dist == "archlinux")
|
||||
{
|
||||
dist = "arch";
|
||||
}
|
||||
else if (dist.startsWith("suse"))
|
||||
{
|
||||
if(lsb.description.startsWith("opensuse"))
|
||||
{
|
||||
dist = "opensuse";
|
||||
}
|
||||
else if (lsb.description.startsWith("suse linux enterprise"))
|
||||
{
|
||||
dist = "sles";
|
||||
}
|
||||
}
|
||||
else if (dist == "debian" and vers == "testing")
|
||||
{
|
||||
vers = lsb.codename;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ubuntu, debian, gentoo, scientific, slackware, ... ?
|
||||
auto parts = dist.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
if(parts.size())
|
||||
{
|
||||
dist = parts[0];
|
||||
}
|
||||
}
|
||||
if(!dist.isEmpty())
|
||||
{
|
||||
out.distributionName = dist;
|
||||
out.distributionVersion = vers;
|
||||
}
|
||||
QString dist = lsb.distributor;
|
||||
QString vers = lsb.version;
|
||||
if(dist.startsWith("redhatenterprise"))
|
||||
{
|
||||
dist = "rhel";
|
||||
}
|
||||
else if(dist == "archlinux")
|
||||
{
|
||||
dist = "arch";
|
||||
}
|
||||
else if (dist.startsWith("suse"))
|
||||
{
|
||||
if(lsb.description.startsWith("opensuse"))
|
||||
{
|
||||
dist = "opensuse";
|
||||
}
|
||||
else if (lsb.description.startsWith("suse linux enterprise"))
|
||||
{
|
||||
dist = "sles";
|
||||
}
|
||||
}
|
||||
else if (dist == "debian" and vers == "testing")
|
||||
{
|
||||
vers = lsb.codename;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ubuntu, debian, gentoo, scientific, slackware, ... ?
|
||||
auto parts = dist.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
if(parts.size())
|
||||
{
|
||||
dist = parts[0];
|
||||
}
|
||||
}
|
||||
if(!dist.isEmpty())
|
||||
{
|
||||
out.distributionName = dist;
|
||||
out.distributionVersion = vers;
|
||||
}
|
||||
}
|
||||
|
||||
Sys::DistributionInfo Sys::read_lsb_release()
|
||||
{
|
||||
LsbInfo lsb;
|
||||
if(!main_lsb_info(lsb))
|
||||
{
|
||||
if(!fallback_lsb_info(lsb))
|
||||
{
|
||||
return Sys::DistributionInfo();
|
||||
}
|
||||
}
|
||||
Sys::DistributionInfo out;
|
||||
lsb_postprocess(lsb, out);
|
||||
return out;
|
||||
LsbInfo lsb;
|
||||
if(!main_lsb_info(lsb))
|
||||
{
|
||||
if(!fallback_lsb_info(lsb))
|
||||
{
|
||||
return Sys::DistributionInfo();
|
||||
}
|
||||
}
|
||||
Sys::DistributionInfo out;
|
||||
lsb_postprocess(lsb, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
QString Sys::_extract_distribution(const QString & x)
|
||||
{
|
||||
QString release = x.toLower();
|
||||
if (release.startsWith("red hat enterprise"))
|
||||
{
|
||||
return "rhel";
|
||||
}
|
||||
if (release.startsWith("suse linux enterprise"))
|
||||
{
|
||||
return "sles";
|
||||
}
|
||||
QStringList list = release.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
if(list.size())
|
||||
{
|
||||
return list[0];
|
||||
}
|
||||
return QString();
|
||||
QString release = x.toLower();
|
||||
if (release.startsWith("red hat enterprise"))
|
||||
{
|
||||
return "rhel";
|
||||
}
|
||||
if (release.startsWith("suse linux enterprise"))
|
||||
{
|
||||
return "sles";
|
||||
}
|
||||
QStringList list = release.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
if(list.size())
|
||||
{
|
||||
return list[0];
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString Sys::_extract_version(const QString & x)
|
||||
{
|
||||
QRegExp versionish_string("\\d+(?:\\.\\d+)*$");
|
||||
QStringList list = x.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
for(int i = list.size() - 1; i >= 0; --i)
|
||||
{
|
||||
QString chunk = list[i];
|
||||
if(versionish_string.exactMatch(chunk))
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
QRegExp versionish_string("\\d+(?:\\.\\d+)*$");
|
||||
QStringList list = x.split(QRegExp("\\s+"), QString::SkipEmptyParts);
|
||||
for(int i = list.size() - 1; i >= 0; --i)
|
||||
{
|
||||
QString chunk = list[i];
|
||||
if(versionish_string.exactMatch(chunk))
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
Sys::DistributionInfo Sys::read_legacy_release()
|
||||
{
|
||||
struct checkEntry
|
||||
{
|
||||
QString file;
|
||||
std::function<QString(const QString &)> extract_distro;
|
||||
std::function<QString(const QString &)> extract_version;
|
||||
};
|
||||
QList<checkEntry> checks =
|
||||
{
|
||||
{"/etc/arch-release", [](const QString &){ return "arch";}, [](const QString &){ return "rolling";}},
|
||||
{"/etc/slackware-version", &Sys::_extract_distribution, &Sys::_extract_version},
|
||||
{QString(), &Sys::_extract_distribution, &Sys::_extract_version},
|
||||
{"/etc/debian_version", [](const QString &){ return "debian";}, [](const QString & x){ return x;}},
|
||||
};
|
||||
for(auto & check: checks)
|
||||
{
|
||||
QStringList files;
|
||||
if(check.file.isNull())
|
||||
{
|
||||
QDir etcDir("/etc");
|
||||
etcDir.setNameFilters({"*-release"});
|
||||
etcDir.setFilter(QDir::Files | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden);
|
||||
files = etcDir.entryList();
|
||||
}
|
||||
else
|
||||
{
|
||||
files.append(check.file);
|
||||
}
|
||||
for (auto file : files)
|
||||
{
|
||||
QFile relfile(file);
|
||||
if(!relfile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
continue;
|
||||
QString contents = QString::fromUtf8(relfile.readLine()).trimmed();
|
||||
QString dist = check.extract_distro(contents);
|
||||
QString vers = check.extract_version(contents);
|
||||
if(!dist.isEmpty())
|
||||
{
|
||||
Sys::DistributionInfo out;
|
||||
out.distributionName = dist;
|
||||
out.distributionVersion = vers;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Sys::DistributionInfo();
|
||||
struct checkEntry
|
||||
{
|
||||
QString file;
|
||||
std::function<QString(const QString &)> extract_distro;
|
||||
std::function<QString(const QString &)> extract_version;
|
||||
};
|
||||
QList<checkEntry> checks =
|
||||
{
|
||||
{"/etc/arch-release", [](const QString &){ return "arch";}, [](const QString &){ return "rolling";}},
|
||||
{"/etc/slackware-version", &Sys::_extract_distribution, &Sys::_extract_version},
|
||||
{QString(), &Sys::_extract_distribution, &Sys::_extract_version},
|
||||
{"/etc/debian_version", [](const QString &){ return "debian";}, [](const QString & x){ return x;}},
|
||||
};
|
||||
for(auto & check: checks)
|
||||
{
|
||||
QStringList files;
|
||||
if(check.file.isNull())
|
||||
{
|
||||
QDir etcDir("/etc");
|
||||
etcDir.setNameFilters({"*-release"});
|
||||
etcDir.setFilter(QDir::Files | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden);
|
||||
files = etcDir.entryList();
|
||||
}
|
||||
else
|
||||
{
|
||||
files.append(check.file);
|
||||
}
|
||||
for (auto file : files)
|
||||
{
|
||||
QFile relfile(file);
|
||||
if(!relfile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
continue;
|
||||
QString contents = QString::fromUtf8(relfile.readLine()).trimmed();
|
||||
QString dist = check.extract_distro(contents);
|
||||
QString vers = check.extract_version(contents);
|
||||
if(!dist.isEmpty())
|
||||
{
|
||||
Sys::DistributionInfo out;
|
||||
out.distributionName = dist;
|
||||
out.distributionVersion = vers;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Sys::DistributionInfo();
|
||||
}
|
||||
|
||||
|
@ -4,44 +4,44 @@
|
||||
|
||||
Sys::KernelInfo Sys::getKernelInfo()
|
||||
{
|
||||
Sys::KernelInfo out;
|
||||
struct utsname buf;
|
||||
uname(&buf);
|
||||
out.kernelName = buf.sysname;
|
||||
out.kernelVersion = buf.release;
|
||||
return out;
|
||||
Sys::KernelInfo out;
|
||||
struct utsname buf;
|
||||
uname(&buf);
|
||||
out.kernelName = buf.sysname;
|
||||
out.kernelVersion = buf.release;
|
||||
return out;
|
||||
}
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
uint64_t Sys::getSystemRam()
|
||||
{
|
||||
uint64_t memsize;
|
||||
size_t memsizesize = sizeof(memsize);
|
||||
if(!sysctlbyname("hw.memsize", &memsize, &memsizesize, NULL, 0))
|
||||
{
|
||||
return memsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint64_t memsize;
|
||||
size_t memsizesize = sizeof(memsize);
|
||||
if(!sysctlbyname("hw.memsize", &memsize, &memsizesize, NULL, 0))
|
||||
{
|
||||
return memsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sys::isCPU64bit()
|
||||
{
|
||||
// not even going to pretend I'm going to support anything else
|
||||
return true;
|
||||
// not even going to pretend I'm going to support anything else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sys::isSystem64bit()
|
||||
{
|
||||
// yep. maybe when we have 128bit CPUs on consumer devices.
|
||||
return true;
|
||||
// yep. maybe when we have 128bit CPUs on consumer devices.
|
||||
return true;
|
||||
}
|
||||
|
||||
Sys::DistributionInfo Sys::getDistributionInfo()
|
||||
{
|
||||
DistributionInfo result;
|
||||
return result;
|
||||
DistributionInfo result;
|
||||
return result;
|
||||
}
|
||||
|
@ -5,24 +5,24 @@
|
||||
|
||||
class SysTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
private
|
||||
slots:
|
||||
|
||||
void test_kernelNotNull()
|
||||
{
|
||||
auto kinfo = Sys::getKernelInfo();
|
||||
QVERIFY(!kinfo.kernelName.isEmpty());
|
||||
QVERIFY(kinfo.kernelVersion != "0.0");
|
||||
}
|
||||
void test_kernelNotNull()
|
||||
{
|
||||
auto kinfo = Sys::getKernelInfo();
|
||||
QVERIFY(!kinfo.kernelName.isEmpty());
|
||||
QVERIFY(kinfo.kernelVersion != "0.0");
|
||||
}
|
||||
/*
|
||||
void test_systemDistroNotNull()
|
||||
{
|
||||
auto kinfo = Sys::getDistributionInfo();
|
||||
QVERIFY(!kinfo.distributionName.isEmpty());
|
||||
QVERIFY(!kinfo.distributionVersion.isEmpty());
|
||||
qDebug() << "Distro: " << kinfo.distributionName << "version" << kinfo.distributionVersion;
|
||||
}
|
||||
void test_systemDistroNotNull()
|
||||
{
|
||||
auto kinfo = Sys::getDistributionInfo();
|
||||
QVERIFY(!kinfo.distributionName.isEmpty());
|
||||
QVERIFY(!kinfo.distributionVersion.isEmpty());
|
||||
qDebug() << "Distro: " << kinfo.distributionName << "version" << kinfo.distributionVersion;
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
|
@ -7,69 +7,69 @@
|
||||
|
||||
Sys::KernelInfo Sys::getKernelInfo()
|
||||
{
|
||||
Sys::KernelInfo out;
|
||||
struct utsname buf;
|
||||
uname(&buf);
|
||||
out.kernelName = buf.sysname;
|
||||
out.kernelVersion = buf.release;
|
||||
return out;
|
||||
Sys::KernelInfo out;
|
||||
struct utsname buf;
|
||||
uname(&buf);
|
||||
out.kernelName = buf.sysname;
|
||||
out.kernelVersion = buf.release;
|
||||
return out;
|
||||
}
|
||||
|
||||
uint64_t Sys::getSystemRam()
|
||||
{
|
||||
std::string token;
|
||||
std::ifstream file("/proc/meminfo");
|
||||
while(file >> token)
|
||||
{
|
||||
if(token == "MemTotal:")
|
||||
{
|
||||
uint64_t mem;
|
||||
if(file >> mem)
|
||||
{
|
||||
return mem * 1024ull;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// ignore rest of the line
|
||||
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
}
|
||||
return 0; // nothing found
|
||||
std::string token;
|
||||
std::ifstream file("/proc/meminfo");
|
||||
while(file >> token)
|
||||
{
|
||||
if(token == "MemTotal:")
|
||||
{
|
||||
uint64_t mem;
|
||||
if(file >> mem)
|
||||
{
|
||||
return mem * 1024ull;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// ignore rest of the line
|
||||
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||
}
|
||||
return 0; // nothing found
|
||||
}
|
||||
|
||||
bool Sys::isCPU64bit()
|
||||
{
|
||||
return isSystem64bit();
|
||||
return isSystem64bit();
|
||||
}
|
||||
|
||||
bool Sys::isSystem64bit()
|
||||
{
|
||||
// kernel build arch on linux
|
||||
return QSysInfo::currentCpuArchitecture() == "x86_64";
|
||||
// kernel build arch on linux
|
||||
return QSysInfo::currentCpuArchitecture() == "x86_64";
|
||||
}
|
||||
|
||||
Sys::DistributionInfo Sys::getDistributionInfo()
|
||||
{
|
||||
DistributionInfo systemd_info = read_os_release();
|
||||
DistributionInfo lsb_info = read_lsb_release();
|
||||
DistributionInfo legacy_info = read_legacy_release();
|
||||
DistributionInfo result = systemd_info + lsb_info + legacy_info;
|
||||
if(result.distributionName.isNull())
|
||||
{
|
||||
result.distributionName = "unknown";
|
||||
}
|
||||
if(result.distributionVersion.isNull())
|
||||
{
|
||||
if(result.distributionName == "arch")
|
||||
{
|
||||
result.distributionVersion = "rolling";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.distributionVersion = "unknown";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
DistributionInfo systemd_info = read_os_release();
|
||||
DistributionInfo lsb_info = read_lsb_release();
|
||||
DistributionInfo legacy_info = read_legacy_release();
|
||||
DistributionInfo result = systemd_info + lsb_info + legacy_info;
|
||||
if(result.distributionName.isNull())
|
||||
{
|
||||
result.distributionName = "unknown";
|
||||
}
|
||||
if(result.distributionVersion.isNull())
|
||||
{
|
||||
if(result.distributionName == "arch")
|
||||
{
|
||||
result.distributionVersion = "rolling";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.distributionVersion = "unknown";
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -4,49 +4,49 @@
|
||||
|
||||
Sys::KernelInfo Sys::getKernelInfo()
|
||||
{
|
||||
Sys::KernelInfo out;
|
||||
out.kernelName = "Windows";
|
||||
OSVERSIONINFOW osvi;
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOW));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
||||
GetVersionExW(&osvi);
|
||||
out.kernelVersion = QString("%1.%2").arg(osvi.dwMajorVersion).arg(osvi.dwMinorVersion);
|
||||
return out;
|
||||
Sys::KernelInfo out;
|
||||
out.kernelName = "Windows";
|
||||
OSVERSIONINFOW osvi;
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOW));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
|
||||
GetVersionExW(&osvi);
|
||||
out.kernelVersion = QString("%1.%2").arg(osvi.dwMajorVersion).arg(osvi.dwMinorVersion);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint64_t Sys::getSystemRam()
|
||||
{
|
||||
MEMORYSTATUSEX status;
|
||||
status.dwLength = sizeof(status);
|
||||
GlobalMemoryStatusEx( &status );
|
||||
// bytes
|
||||
return (uint64_t)status.ullTotalPhys;
|
||||
MEMORYSTATUSEX status;
|
||||
status.dwLength = sizeof(status);
|
||||
GlobalMemoryStatusEx( &status );
|
||||
// bytes
|
||||
return (uint64_t)status.ullTotalPhys;
|
||||
}
|
||||
|
||||
bool Sys::isSystem64bit()
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
return true;
|
||||
return true;
|
||||
#elif defined(_WIN32)
|
||||
BOOL f64 = false;
|
||||
return IsWow64Process(GetCurrentProcess(), &f64) && f64;
|
||||
BOOL f64 = false;
|
||||
return IsWow64Process(GetCurrentProcess(), &f64) && f64;
|
||||
#else
|
||||
// it's some other kind of system...
|
||||
return false;
|
||||
// it's some other kind of system...
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Sys::isCPU64bit()
|
||||
{
|
||||
SYSTEM_INFO info;
|
||||
ZeroMemory(&info, sizeof(SYSTEM_INFO));
|
||||
GetNativeSystemInfo(&info);
|
||||
auto arch = info.wProcessorArchitecture;
|
||||
return arch == PROCESSOR_ARCHITECTURE_AMD64 || arch == PROCESSOR_ARCHITECTURE_IA64;
|
||||
SYSTEM_INFO info;
|
||||
ZeroMemory(&info, sizeof(SYSTEM_INFO));
|
||||
GetNativeSystemInfo(&info);
|
||||
auto arch = info.wProcessorArchitecture;
|
||||
return arch == PROCESSOR_ARCHITECTURE_AMD64 || arch == PROCESSOR_ARCHITECTURE_IA64;
|
||||
}
|
||||
|
||||
Sys::DistributionInfo Sys::getDistributionInfo()
|
||||
{
|
||||
DistributionInfo result;
|
||||
return result;
|
||||
DistributionInfo result;
|
||||
return result;
|
||||
}
|
||||
|
@ -9,18 +9,18 @@ option(XZ_BUILD_MINIDEC "Build a tiny utility that decompresses xz streams" OFF)
|
||||
# tweak this list and xz.h to fit your needs
|
||||
|
||||
set(XZ_SOURCES
|
||||
src/xz_crc32.c
|
||||
src/xz_crc64.c
|
||||
src/xz_dec_lzma2.c
|
||||
src/xz_dec_stream.c
|
||||
# src/xz_dec_bcj.c
|
||||
src/xz_crc32.c
|
||||
src/xz_crc64.c
|
||||
src/xz_dec_lzma2.c
|
||||
src/xz_dec_stream.c
|
||||
# src/xz_dec_bcj.c
|
||||
)
|
||||
add_library(xz-embedded STATIC ${XZ_SOURCES})
|
||||
target_include_directories(xz-embedded PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
set_property(TARGET xz-embedded PROPERTY C_STANDARD 99)
|
||||
|
||||
if(${XZ_BUILD_MINIDEC})
|
||||
add_executable(xzminidec xzminidec.c)
|
||||
target_link_libraries(xzminidec xz-embedded)
|
||||
set_property(TARGET xzminidec PROPERTY C_STANDARD 99)
|
||||
add_executable(xzminidec xzminidec.c)
|
||||
target_link_libraries(xzminidec xz-embedded)
|
||||
set_property(TARGET xzminidec PROPERTY C_STANDARD 99)
|
||||
endif()
|
||||
|
@ -69,9 +69,9 @@ extern "C" {
|
||||
*/
|
||||
enum xz_mode
|
||||
{
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
@ -126,15 +126,15 @@ enum xz_mode
|
||||
*/
|
||||
enum xz_ret
|
||||
{
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
@ -155,13 +155,13 @@ enum xz_ret
|
||||
*/
|
||||
struct xz_buf
|
||||
{
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -74,36 +74,36 @@ typedef unsigned char bool;
|
||||
#ifndef get_unaligned_le32
|
||||
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) |
|
||||
((uint32_t)buf[3] << 24);
|
||||
return (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) |
|
||||
((uint32_t)buf[3] << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef get_unaligned_be32
|
||||
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)(buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) |
|
||||
(uint32_t)buf[3];
|
||||
return (uint32_t)(buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) |
|
||||
(uint32_t)buf[3];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_le32
|
||||
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
buf[0] = (uint8_t)val;
|
||||
buf[1] = (uint8_t)(val >> 8);
|
||||
buf[2] = (uint8_t)(val >> 16);
|
||||
buf[3] = (uint8_t)(val >> 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef put_unaligned_be32
|
||||
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
|
||||
{
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
buf[0] = (uint8_t)(val >> 24);
|
||||
buf[1] = (uint8_t)(val >> 16);
|
||||
buf[2] = (uint8_t)(val >> 8);
|
||||
buf[3] = (uint8_t)val;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -29,33 +29,33 @@ STATIC_RW_DATA uint32_t xz_crc32_table[256];
|
||||
|
||||
XZ_EXTERN void xz_crc32_init(void)
|
||||
{
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
const uint32_t poly = 0xEDB88320;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
|
||||
xz_crc32_table[i] = r;
|
||||
}
|
||||
xz_crc32_table[i] = r;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
while (size != 0)
|
||||
{
|
||||
crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
return ~crc;
|
||||
}
|
||||
|
@ -20,33 +20,33 @@ STATIC_RW_DATA uint64_t xz_crc64_table[256];
|
||||
|
||||
XZ_EXTERN void xz_crc64_init(void)
|
||||
{
|
||||
const uint64_t poly = 0xC96C5795D7870F42;
|
||||
const uint64_t poly = 0xC96C5795D7870F42;
|
||||
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint64_t r;
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint64_t r;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
for (i = 0; i < 256; ++i)
|
||||
{
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (poly & ~((r & 1) - 1));
|
||||
|
||||
xz_crc64_table[i] = r;
|
||||
}
|
||||
xz_crc64_table[i] = r;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
crc = ~crc;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
while (size != 0)
|
||||
{
|
||||
crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
return ~crc;
|
||||
}
|
||||
|
@ -18,64 +18,64 @@
|
||||
|
||||
struct xz_dec_bcj
|
||||
{
|
||||
/* Type of the BCJ filter being used */
|
||||
enum
|
||||
{
|
||||
BCJ_X86 = 4, /* x86 or x86-64 */
|
||||
BCJ_POWERPC = 5, /* Big endian only */
|
||||
BCJ_IA64 = 6, /* Big or little endian */
|
||||
BCJ_ARM = 7, /* Little endian only */
|
||||
BCJ_ARMTHUMB = 8, /* Little endian only */
|
||||
BCJ_SPARC = 9 /* Big or little endian */
|
||||
} type;
|
||||
/* Type of the BCJ filter being used */
|
||||
enum
|
||||
{
|
||||
BCJ_X86 = 4, /* x86 or x86-64 */
|
||||
BCJ_POWERPC = 5, /* Big endian only */
|
||||
BCJ_IA64 = 6, /* Big or little endian */
|
||||
BCJ_ARM = 7, /* Little endian only */
|
||||
BCJ_ARMTHUMB = 8, /* Little endian only */
|
||||
BCJ_SPARC = 9 /* Big or little endian */
|
||||
} type;
|
||||
|
||||
/*
|
||||
* Return value of the next filter in the chain. We need to preserve
|
||||
* this information across calls, because we must not call the next
|
||||
* filter anymore once it has returned XZ_STREAM_END.
|
||||
*/
|
||||
enum xz_ret ret;
|
||||
/*
|
||||
* Return value of the next filter in the chain. We need to preserve
|
||||
* this information across calls, because we must not call the next
|
||||
* filter anymore once it has returned XZ_STREAM_END.
|
||||
*/
|
||||
enum xz_ret ret;
|
||||
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
/* True if we are operating in single-call mode. */
|
||||
bool single_call;
|
||||
|
||||
/*
|
||||
* Absolute position relative to the beginning of the uncompressed
|
||||
* data (in a single .xz Block). We care only about the lowest 32
|
||||
* bits so this doesn't need to be uint64_t even with big files.
|
||||
*/
|
||||
uint32_t pos;
|
||||
/*
|
||||
* Absolute position relative to the beginning of the uncompressed
|
||||
* data (in a single .xz Block). We care only about the lowest 32
|
||||
* bits so this doesn't need to be uint64_t even with big files.
|
||||
*/
|
||||
uint32_t pos;
|
||||
|
||||
/* x86 filter state */
|
||||
uint32_t x86_prev_mask;
|
||||
/* x86 filter state */
|
||||
uint32_t x86_prev_mask;
|
||||
|
||||
/* Temporary space to hold the variables from struct xz_buf */
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
/* Temporary space to hold the variables from struct xz_buf */
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
|
||||
struct
|
||||
{
|
||||
/* Amount of already filtered data in the beginning of buf */
|
||||
size_t filtered;
|
||||
struct
|
||||
{
|
||||
/* Amount of already filtered data in the beginning of buf */
|
||||
size_t filtered;
|
||||
|
||||
/* Total amount of data currently stored in buf */
|
||||
size_t size;
|
||||
/* Total amount of data currently stored in buf */
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Buffer to hold a mix of filtered and unfiltered data. This
|
||||
* needs to be big enough to hold Alignment + 2 * Look-ahead:
|
||||
*
|
||||
* Type Alignment Look-ahead
|
||||
* x86 1 4
|
||||
* PowerPC 4 0
|
||||
* IA-64 16 0
|
||||
* ARM 4 0
|
||||
* ARM-Thumb 2 2
|
||||
* SPARC 4 0
|
||||
*/
|
||||
uint8_t buf[16];
|
||||
} temp;
|
||||
/*
|
||||
* Buffer to hold a mix of filtered and unfiltered data. This
|
||||
* needs to be big enough to hold Alignment + 2 * Look-ahead:
|
||||
*
|
||||
* Type Alignment Look-ahead
|
||||
* x86 1 4
|
||||
* PowerPC 4 0
|
||||
* IA-64 16 0
|
||||
* ARM 4 0
|
||||
* ARM-Thumb 2 2
|
||||
* SPARC 4 0
|
||||
*/
|
||||
uint8_t buf[16];
|
||||
} temp;
|
||||
};
|
||||
|
||||
#ifdef XZ_DEC_X86
|
||||
@ -85,264 +85,264 @@ struct xz_dec_bcj
|
||||
*/
|
||||
static inline int bcj_x86_test_msbyte(uint8_t b)
|
||||
{
|
||||
return b == 0x00 || b == 0xFF;
|
||||
return b == 0x00 || b == 0xFF;
|
||||
}
|
||||
|
||||
static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const bool mask_to_allowed_status[8] = {true, true, true, false,
|
||||
true, false, false, false};
|
||||
static const bool mask_to_allowed_status[8] = {true, true, true, false,
|
||||
true, false, false, false};
|
||||
|
||||
static const uint8_t mask_to_bit_num[8] = {0, 1, 2, 2, 3, 3, 3, 3};
|
||||
static const uint8_t mask_to_bit_num[8] = {0, 1, 2, 2, 3, 3, 3, 3};
|
||||
|
||||
size_t i;
|
||||
size_t prev_pos = (size_t) - 1;
|
||||
uint32_t prev_mask = s->x86_prev_mask;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t j;
|
||||
uint8_t b;
|
||||
size_t i;
|
||||
size_t prev_pos = (size_t) - 1;
|
||||
uint32_t prev_mask = s->x86_prev_mask;
|
||||
uint32_t src;
|
||||
uint32_t dest;
|
||||
uint32_t j;
|
||||
uint8_t b;
|
||||
|
||||
if (size <= 4)
|
||||
return 0;
|
||||
if (size <= 4)
|
||||
return 0;
|
||||
|
||||
size -= 4;
|
||||
for (i = 0; i < size; ++i)
|
||||
{
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
size -= 4;
|
||||
for (i = 0; i < size; ++i)
|
||||
{
|
||||
if ((buf[i] & 0xFE) != 0xE8)
|
||||
continue;
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3)
|
||||
{
|
||||
prev_mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0)
|
||||
{
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask] || bcj_x86_test_msbyte(b))
|
||||
{
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_pos = i - prev_pos;
|
||||
if (prev_pos > 3)
|
||||
{
|
||||
prev_mask = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
|
||||
if (prev_mask != 0)
|
||||
{
|
||||
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
|
||||
if (!mask_to_allowed_status[prev_mask] || bcj_x86_test_msbyte(b))
|
||||
{
|
||||
prev_pos = i;
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i;
|
||||
prev_pos = i;
|
||||
|
||||
if (bcj_x86_test_msbyte(buf[i + 4]))
|
||||
{
|
||||
src = get_unaligned_le32(buf + i + 1);
|
||||
while (true)
|
||||
{
|
||||
dest = src - (s->pos + (uint32_t)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
if (bcj_x86_test_msbyte(buf[i + 4]))
|
||||
{
|
||||
src = get_unaligned_le32(buf + i + 1);
|
||||
while (true)
|
||||
{
|
||||
dest = src - (s->pos + (uint32_t)i + 5);
|
||||
if (prev_mask == 0)
|
||||
break;
|
||||
|
||||
j = mask_to_bit_num[prev_mask] * 8;
|
||||
b = (uint8_t)(dest >> (24 - j));
|
||||
if (!bcj_x86_test_msbyte(b))
|
||||
break;
|
||||
j = mask_to_bit_num[prev_mask] * 8;
|
||||
b = (uint8_t)(dest >> (24 - j));
|
||||
if (!bcj_x86_test_msbyte(b))
|
||||
break;
|
||||
|
||||
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
|
||||
}
|
||||
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
|
||||
}
|
||||
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= (uint32_t)0 - (dest & 0x01000000);
|
||||
put_unaligned_le32(dest, buf + i + 1);
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
dest &= 0x01FFFFFF;
|
||||
dest |= (uint32_t)0 - (dest & 0x01000000);
|
||||
put_unaligned_le32(dest, buf + i + 1);
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_mask = (prev_mask << 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
prev_pos = i - prev_pos;
|
||||
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
return i;
|
||||
prev_pos = i - prev_pos;
|
||||
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr & 0xFC000003) == 0x48000001)
|
||||
{
|
||||
instr &= 0x03FFFFFC;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr &= 0x03FFFFFC;
|
||||
instr |= 0x48000001;
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr & 0xFC000003) == 0x48000001)
|
||||
{
|
||||
instr &= 0x03FFFFFC;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr &= 0x03FFFFFC;
|
||||
instr |= 0x48000001;
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_IA64
|
||||
static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
static const uint8_t branch_table[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0};
|
||||
static const uint8_t branch_table[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 6, 6, 0, 0, 7, 7, 4, 4, 0, 0, 4, 4, 0, 0};
|
||||
|
||||
/*
|
||||
* The local variables take a little bit stack space, but it's less
|
||||
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
|
||||
* stack usage here without doing that for the LZMA2 decoder too.
|
||||
*/
|
||||
/*
|
||||
* The local variables take a little bit stack space, but it's less
|
||||
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
|
||||
* stack usage here without doing that for the LZMA2 decoder too.
|
||||
*/
|
||||
|
||||
/* Loop counters */
|
||||
size_t i;
|
||||
size_t j;
|
||||
/* Loop counters */
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
|
||||
uint32_t slot;
|
||||
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
|
||||
uint32_t slot;
|
||||
|
||||
/* Bitwise offset of the instruction indicated by slot */
|
||||
uint32_t bit_pos;
|
||||
/* Bitwise offset of the instruction indicated by slot */
|
||||
uint32_t bit_pos;
|
||||
|
||||
/* bit_pos split into byte and bit parts */
|
||||
uint32_t byte_pos;
|
||||
uint32_t bit_res;
|
||||
/* bit_pos split into byte and bit parts */
|
||||
uint32_t byte_pos;
|
||||
uint32_t bit_res;
|
||||
|
||||
/* Address part of an instruction */
|
||||
uint32_t addr;
|
||||
/* Address part of an instruction */
|
||||
uint32_t addr;
|
||||
|
||||
/* Mask used to detect which instructions to convert */
|
||||
uint32_t mask;
|
||||
/* Mask used to detect which instructions to convert */
|
||||
uint32_t mask;
|
||||
|
||||
/* 41-bit instruction stored somewhere in the lowest 48 bits */
|
||||
uint64_t instr;
|
||||
/* 41-bit instruction stored somewhere in the lowest 48 bits */
|
||||
uint64_t instr;
|
||||
|
||||
/* Instruction normalized with bit_res for easier manipulation */
|
||||
uint64_t norm;
|
||||
/* Instruction normalized with bit_res for easier manipulation */
|
||||
uint64_t norm;
|
||||
|
||||
for (i = 0; i + 16 <= size; i += 16)
|
||||
{
|
||||
mask = branch_table[buf[i] & 0x1F];
|
||||
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41)
|
||||
{
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
for (i = 0; i + 16 <= size; i += 16)
|
||||
{
|
||||
mask = branch_table[buf[i] & 0x1F];
|
||||
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41)
|
||||
{
|
||||
if (((mask >> slot) & 1) == 0)
|
||||
continue;
|
||||
|
||||
byte_pos = bit_pos >> 3;
|
||||
bit_res = bit_pos & 7;
|
||||
instr = 0;
|
||||
for (j = 0; j < 6; ++j)
|
||||
instr |= (uint64_t)(buf[i + j + byte_pos]) << (8 * j);
|
||||
byte_pos = bit_pos >> 3;
|
||||
bit_res = bit_pos & 7;
|
||||
instr = 0;
|
||||
for (j = 0; j < 6; ++j)
|
||||
instr |= (uint64_t)(buf[i + j + byte_pos]) << (8 * j);
|
||||
|
||||
norm = instr >> bit_res;
|
||||
norm = instr >> bit_res;
|
||||
|
||||
if (((norm >> 37) & 0x0F) == 0x05 && ((norm >> 9) & 0x07) == 0)
|
||||
{
|
||||
addr = (norm >> 13) & 0x0FFFFF;
|
||||
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
|
||||
addr <<= 4;
|
||||
addr -= s->pos + (uint32_t)i;
|
||||
addr >>= 4;
|
||||
if (((norm >> 37) & 0x0F) == 0x05 && ((norm >> 9) & 0x07) == 0)
|
||||
{
|
||||
addr = (norm >> 13) & 0x0FFFFF;
|
||||
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
|
||||
addr <<= 4;
|
||||
addr -= s->pos + (uint32_t)i;
|
||||
addr >>= 4;
|
||||
|
||||
norm &= ~((uint64_t)0x8FFFFF << 13);
|
||||
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
|
||||
norm |= (uint64_t)(addr & 0x100000) << (36 - 20);
|
||||
norm &= ~((uint64_t)0x8FFFFF << 13);
|
||||
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
|
||||
norm |= (uint64_t)(addr & 0x100000) << (36 - 20);
|
||||
|
||||
instr &= (1 << bit_res) - 1;
|
||||
instr |= norm << bit_res;
|
||||
instr &= (1 << bit_res) - 1;
|
||||
instr |= norm << bit_res;
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
buf[i + j + byte_pos] = (uint8_t)(instr >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 6; j++)
|
||||
buf[i + j + byte_pos] = (uint8_t)(instr >> (8 * j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARM
|
||||
static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
if (buf[i + 3] == 0xEB)
|
||||
{
|
||||
addr =
|
||||
(uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) | ((uint32_t)buf[i + 2] << 16);
|
||||
addr <<= 2;
|
||||
addr -= s->pos + (uint32_t)i + 8;
|
||||
addr >>= 2;
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
}
|
||||
}
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
if (buf[i + 3] == 0xEB)
|
||||
{
|
||||
addr =
|
||||
(uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) | ((uint32_t)buf[i + 2] << 16);
|
||||
addr <<= 2;
|
||||
addr -= s->pos + (uint32_t)i + 8;
|
||||
addr >>= 2;
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
size_t i;
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 2)
|
||||
{
|
||||
if ((buf[i + 1] & 0xF8) == 0xF0 && (buf[i + 3] & 0xF8) == 0xF8)
|
||||
{
|
||||
addr = (((uint32_t)buf[i + 1] & 0x07) << 19) | ((uint32_t)buf[i] << 11) |
|
||||
(((uint32_t)buf[i + 3] & 0x07) << 8) | (uint32_t)buf[i + 2];
|
||||
addr <<= 1;
|
||||
addr -= s->pos + (uint32_t)i + 4;
|
||||
addr >>= 1;
|
||||
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
|
||||
buf[i] = (uint8_t)(addr >> 11);
|
||||
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
|
||||
buf[i + 2] = (uint8_t)addr;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
for (i = 0; i + 4 <= size; i += 2)
|
||||
{
|
||||
if ((buf[i + 1] & 0xF8) == 0xF0 && (buf[i + 3] & 0xF8) == 0xF8)
|
||||
{
|
||||
addr = (((uint32_t)buf[i + 1] & 0x07) << 19) | ((uint32_t)buf[i] << 11) |
|
||||
(((uint32_t)buf[i + 3] & 0x07) << 8) | (uint32_t)buf[i + 2];
|
||||
addr <<= 1;
|
||||
addr -= s->pos + (uint32_t)i + 4;
|
||||
addr >>= 1;
|
||||
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
|
||||
buf[i] = (uint8_t)(addr >> 11);
|
||||
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
|
||||
buf[i + 2] = (uint8_t)addr;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XZ_DEC_SPARC
|
||||
static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
size_t i;
|
||||
uint32_t instr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF)
|
||||
{
|
||||
instr <<= 2;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr =
|
||||
((uint32_t)0x40000000 - (instr & 0x400000)) | 0x40000000 | (instr & 0x3FFFFF);
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i + 4 <= size; i += 4)
|
||||
{
|
||||
instr = get_unaligned_be32(buf + i);
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF)
|
||||
{
|
||||
instr <<= 2;
|
||||
instr -= s->pos + (uint32_t)i;
|
||||
instr >>= 2;
|
||||
instr =
|
||||
((uint32_t)0x40000000 - (instr & 0x400000)) | 0x40000000 | (instr & 0x3FFFFF);
|
||||
put_unaligned_be32(instr, buf + i);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -356,51 +356,51 @@ static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
|
||||
*/
|
||||
static void bcj_apply(struct xz_dec_bcj *s, uint8_t *buf, size_t *pos, size_t size)
|
||||
{
|
||||
size_t filtered;
|
||||
size_t filtered;
|
||||
|
||||
buf += *pos;
|
||||
size -= *pos;
|
||||
buf += *pos;
|
||||
size -= *pos;
|
||||
|
||||
switch (s->type)
|
||||
{
|
||||
switch (s->type)
|
||||
{
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
filtered = bcj_x86(s, buf, size);
|
||||
break;
|
||||
case BCJ_X86:
|
||||
filtered = bcj_x86(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
filtered = bcj_powerpc(s, buf, size);
|
||||
break;
|
||||
case BCJ_POWERPC:
|
||||
filtered = bcj_powerpc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
filtered = bcj_ia64(s, buf, size);
|
||||
break;
|
||||
case BCJ_IA64:
|
||||
filtered = bcj_ia64(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
filtered = bcj_arm(s, buf, size);
|
||||
break;
|
||||
case BCJ_ARM:
|
||||
filtered = bcj_arm(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
filtered = bcj_armthumb(s, buf, size);
|
||||
break;
|
||||
case BCJ_ARMTHUMB:
|
||||
filtered = bcj_armthumb(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
filtered = bcj_sparc(s, buf, size);
|
||||
break;
|
||||
case BCJ_SPARC:
|
||||
filtered = bcj_sparc(s, buf, size);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Never reached but silence compiler warnings. */
|
||||
filtered = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Never reached but silence compiler warnings. */
|
||||
filtered = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*pos += filtered;
|
||||
s->pos += filtered;
|
||||
*pos += filtered;
|
||||
s->pos += filtered;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -410,15 +410,15 @@ static void bcj_apply(struct xz_dec_bcj *s, uint8_t *buf, size_t *pos, size_t si
|
||||
*/
|
||||
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size;
|
||||
size_t copy_size;
|
||||
|
||||
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
|
||||
s->temp.filtered -= copy_size;
|
||||
s->temp.size -= copy_size;
|
||||
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
|
||||
s->temp.filtered -= copy_size;
|
||||
s->temp.size -= copy_size;
|
||||
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -427,162 +427,162 @@ static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
|
||||
* some buffering.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b)
|
||||
struct xz_buf *b)
|
||||
{
|
||||
size_t out_start;
|
||||
size_t out_start;
|
||||
|
||||
/*
|
||||
* Flush pending already filtered data to the output buffer. Return
|
||||
* immediatelly if we couldn't flush everything, or if the next
|
||||
* filter in the chain had already returned XZ_STREAM_END.
|
||||
*/
|
||||
if (s->temp.filtered > 0)
|
||||
{
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
/*
|
||||
* Flush pending already filtered data to the output buffer. Return
|
||||
* immediatelly if we couldn't flush everything, or if the next
|
||||
* filter in the chain had already returned XZ_STREAM_END.
|
||||
*/
|
||||
if (s->temp.filtered > 0)
|
||||
{
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have more output space than what is currently pending in
|
||||
* temp, copy the unfiltered data from temp to the output buffer
|
||||
* and try to fill the output buffer by decoding more data from the
|
||||
* next filter in the chain. Apply the BCJ filter on the new data
|
||||
* in the output buffer. If everything cannot be filtered, copy it
|
||||
* to temp and rewind the output buffer position accordingly.
|
||||
*
|
||||
* This needs to be always run when temp.size == 0 to handle a special
|
||||
* case where the output buffer is full and the next filter has no
|
||||
* more output coming but hasn't returned XZ_STREAM_END yet.
|
||||
*/
|
||||
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0)
|
||||
{
|
||||
out_start = b->out_pos;
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
|
||||
b->out_pos += s->temp.size;
|
||||
/*
|
||||
* If we have more output space than what is currently pending in
|
||||
* temp, copy the unfiltered data from temp to the output buffer
|
||||
* and try to fill the output buffer by decoding more data from the
|
||||
* next filter in the chain. Apply the BCJ filter on the new data
|
||||
* in the output buffer. If everything cannot be filtered, copy it
|
||||
* to temp and rewind the output buffer position accordingly.
|
||||
*
|
||||
* This needs to be always run when temp.size == 0 to handle a special
|
||||
* case where the output buffer is full and the next filter has no
|
||||
* more output coming but hasn't returned XZ_STREAM_END yet.
|
||||
*/
|
||||
if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0)
|
||||
{
|
||||
out_start = b->out_pos;
|
||||
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
|
||||
b->out_pos += s->temp.size;
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
if (s->ret != XZ_STREAM_END && (s->ret != XZ_OK || s->single_call))
|
||||
return s->ret;
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
if (s->ret != XZ_STREAM_END && (s->ret != XZ_OK || s->single_call))
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, b->out, &out_start, b->out_pos);
|
||||
bcj_apply(s, b->out, &out_start, b->out_pos);
|
||||
|
||||
/*
|
||||
* As an exception, if the next filter returned XZ_STREAM_END,
|
||||
* we can do that too, since the last few bytes that remain
|
||||
* unfiltered are meant to remain unfiltered.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
/*
|
||||
* As an exception, if the next filter returned XZ_STREAM_END,
|
||||
* we can do that too, since the last few bytes that remain
|
||||
* unfiltered are meant to remain unfiltered.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
return XZ_STREAM_END;
|
||||
|
||||
s->temp.size = b->out_pos - out_start;
|
||||
b->out_pos -= s->temp.size;
|
||||
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
|
||||
s->temp.size = b->out_pos - out_start;
|
||||
b->out_pos -= s->temp.size;
|
||||
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
|
||||
|
||||
/*
|
||||
* If there wasn't enough input to the next filter to fill
|
||||
* the output buffer with unfiltered data, there's no point
|
||||
* to try decoding more data to temp.
|
||||
*/
|
||||
if (b->out_pos + s->temp.size < b->out_size)
|
||||
return XZ_OK;
|
||||
}
|
||||
/*
|
||||
* If there wasn't enough input to the next filter to fill
|
||||
* the output buffer with unfiltered data, there's no point
|
||||
* to try decoding more data to temp.
|
||||
*/
|
||||
if (b->out_pos + s->temp.size < b->out_size)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have unfiltered data in temp. If the output buffer isn't full
|
||||
* yet, try to fill the temp buffer by decoding more data from the
|
||||
* next filter. Apply the BCJ filter on temp. Then we hopefully can
|
||||
* fill the actual output buffer by copying filtered data from temp.
|
||||
* A mix of filtered and unfiltered data may be left in temp; it will
|
||||
* be taken care on the next call to this function.
|
||||
*/
|
||||
if (b->out_pos < b->out_size)
|
||||
{
|
||||
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
|
||||
s->out = b->out;
|
||||
s->out_pos = b->out_pos;
|
||||
s->out_size = b->out_size;
|
||||
b->out = s->temp.buf;
|
||||
b->out_pos = s->temp.size;
|
||||
b->out_size = sizeof(s->temp.buf);
|
||||
/*
|
||||
* We have unfiltered data in temp. If the output buffer isn't full
|
||||
* yet, try to fill the temp buffer by decoding more data from the
|
||||
* next filter. Apply the BCJ filter on temp. Then we hopefully can
|
||||
* fill the actual output buffer by copying filtered data from temp.
|
||||
* A mix of filtered and unfiltered data may be left in temp; it will
|
||||
* be taken care on the next call to this function.
|
||||
*/
|
||||
if (b->out_pos < b->out_size)
|
||||
{
|
||||
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
|
||||
s->out = b->out;
|
||||
s->out_pos = b->out_pos;
|
||||
s->out_size = b->out_size;
|
||||
b->out = s->temp.buf;
|
||||
b->out_pos = s->temp.size;
|
||||
b->out_size = sizeof(s->temp.buf);
|
||||
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
s->ret = xz_dec_lzma2_run(lzma2, b);
|
||||
|
||||
s->temp.size = b->out_pos;
|
||||
b->out = s->out;
|
||||
b->out_pos = s->out_pos;
|
||||
b->out_size = s->out_size;
|
||||
s->temp.size = b->out_pos;
|
||||
b->out = s->out;
|
||||
b->out_pos = s->out_pos;
|
||||
b->out_size = s->out_size;
|
||||
|
||||
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
|
||||
return s->ret;
|
||||
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
|
||||
return s->ret;
|
||||
|
||||
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
|
||||
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
|
||||
|
||||
/*
|
||||
* If the next filter returned XZ_STREAM_END, we mark that
|
||||
* everything is filtered, since the last unfiltered bytes
|
||||
* of the stream are meant to be left as is.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
s->temp.filtered = s->temp.size;
|
||||
/*
|
||||
* If the next filter returned XZ_STREAM_END, we mark that
|
||||
* everything is filtered, since the last unfiltered bytes
|
||||
* of the stream are meant to be left as is.
|
||||
*/
|
||||
if (s->ret == XZ_STREAM_END)
|
||||
s->temp.filtered = s->temp.size;
|
||||
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
}
|
||||
bcj_flush(s, b);
|
||||
if (s->temp.filtered > 0)
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
return s->ret;
|
||||
return s->ret;
|
||||
}
|
||||
|
||||
XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
|
||||
{
|
||||
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s != NULL)
|
||||
s->single_call = single_call;
|
||||
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (s != NULL)
|
||||
s->single_call = single_call;
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
#ifdef XZ_DEC_X86
|
||||
case BCJ_X86:
|
||||
case BCJ_X86:
|
||||
#endif
|
||||
#ifdef XZ_DEC_POWERPC
|
||||
case BCJ_POWERPC:
|
||||
case BCJ_POWERPC:
|
||||
#endif
|
||||
#ifdef XZ_DEC_IA64
|
||||
case BCJ_IA64:
|
||||
case BCJ_IA64:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARM
|
||||
case BCJ_ARM:
|
||||
case BCJ_ARM:
|
||||
#endif
|
||||
#ifdef XZ_DEC_ARMTHUMB
|
||||
case BCJ_ARMTHUMB:
|
||||
case BCJ_ARMTHUMB:
|
||||
#endif
|
||||
#ifdef XZ_DEC_SPARC
|
||||
case BCJ_SPARC:
|
||||
case BCJ_SPARC:
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unsupported Filter ID */
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
default:
|
||||
/* Unsupported Filter ID */
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
s->type = id;
|
||||
s->ret = XZ_OK;
|
||||
s->pos = 0;
|
||||
s->x86_prev_mask = 0;
|
||||
s->temp.filtered = 0;
|
||||
s->temp.size = 0;
|
||||
s->type = id;
|
||||
s->ret = XZ_OK;
|
||||
s->pos = 0;
|
||||
s->x86_prev_mask = 0;
|
||||
s->temp.filtered = 0;
|
||||
s->temp.size = 0;
|
||||
|
||||
return XZ_OK;
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -41,18 +41,18 @@
|
||||
*/
|
||||
enum lzma_state
|
||||
{
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
STATE_LIT_LIT,
|
||||
STATE_MATCH_LIT_LIT,
|
||||
STATE_REP_LIT_LIT,
|
||||
STATE_SHORTREP_LIT_LIT,
|
||||
STATE_MATCH_LIT,
|
||||
STATE_REP_LIT,
|
||||
STATE_SHORTREP_LIT,
|
||||
STATE_LIT_MATCH,
|
||||
STATE_LIT_LONGREP,
|
||||
STATE_LIT_SHORTREP,
|
||||
STATE_NONLIT_MATCH,
|
||||
STATE_NONLIT_REP
|
||||
};
|
||||
|
||||
/* Total number of states */
|
||||
@ -64,36 +64,36 @@ enum lzma_state
|
||||
/* Indicate that the latest symbol was a literal. */
|
||||
static inline void lzma_state_literal(enum lzma_state *state)
|
||||
{
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
if (*state <= STATE_SHORTREP_LIT_LIT)
|
||||
*state = STATE_LIT_LIT;
|
||||
else if (*state <= STATE_LIT_SHORTREP)
|
||||
*state -= 3;
|
||||
else
|
||||
*state -= 6;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a match. */
|
||||
static inline void lzma_state_match(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
|
||||
}
|
||||
|
||||
/* Indicate that the latest state was a long repeated match. */
|
||||
static inline void lzma_state_long_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Indicate that the latest symbol was a short match. */
|
||||
static inline void lzma_state_short_rep(enum lzma_state *state)
|
||||
{
|
||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
|
||||
}
|
||||
|
||||
/* Test if the previous symbol was a literal. */
|
||||
static inline bool lzma_state_is_literal(enum lzma_state state)
|
||||
{
|
||||
return state < LIT_STATES;
|
||||
return state < LIT_STATES;
|
||||
}
|
||||
|
||||
/* Each literal coder is divided in three sections:
|
||||
@ -147,7 +147,7 @@ static inline bool lzma_state_is_literal(enum lzma_state state)
|
||||
*/
|
||||
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN ? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
return len < DIST_STATES + MATCH_LEN_MIN ? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -94,8 +94,8 @@
|
||||
*/
|
||||
#ifndef XZ_DEC_BCJ
|
||||
#if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) || defined(XZ_DEC_IA64) || \
|
||||
defined(XZ_DEC_ARM) || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) || \
|
||||
defined(XZ_DEC_SPARC)
|
||||
defined(XZ_DEC_ARM) || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) || \
|
||||
defined(XZ_DEC_SPARC)
|
||||
#define XZ_DEC_BCJ
|
||||
#endif
|
||||
#endif
|
||||
@ -141,7 +141,7 @@ XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
|
||||
* must be called directly.
|
||||
*/
|
||||
XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, struct xz_dec_lzma2 *lzma2,
|
||||
struct xz_buf *b);
|
||||
struct xz_buf *b);
|
||||
|
||||
/* Free the memory allocated for the BCJ filters. */
|
||||
#define xz_dec_bcj_end(s) kfree(s)
|
||||
|
@ -50,10 +50,10 @@ typedef uint64_t vli_type;
|
||||
/* Integrity Check types */
|
||||
enum xz_check
|
||||
{
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
XZ_CHECK_NONE = 0,
|
||||
XZ_CHECK_CRC32 = 1,
|
||||
XZ_CHECK_CRC64 = 4,
|
||||
XZ_CHECK_SHA256 = 10
|
||||
};
|
||||
|
||||
/* Maximum possible Check ID */
|
||||
|
@ -24,121 +24,121 @@ static uint8_t out[BUFSIZ];
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct xz_buf b;
|
||||
struct xz_dec *s;
|
||||
enum xz_ret ret;
|
||||
const char *msg;
|
||||
struct xz_buf b;
|
||||
struct xz_dec *s;
|
||||
enum xz_ret ret;
|
||||
const char *msg;
|
||||
|
||||
if (argc >= 2 && strcmp(argv[1], "--help") == 0)
|
||||
{
|
||||
fputs("Uncompress a .xz file from stdin to stdout.\n"
|
||||
"Arguments other than `--help' are ignored.\n",
|
||||
stdout);
|
||||
return 0;
|
||||
}
|
||||
if (argc >= 2 && strcmp(argv[1], "--help") == 0)
|
||||
{
|
||||
fputs("Uncompress a .xz file from stdin to stdout.\n"
|
||||
"Arguments other than `--help' are ignored.\n",
|
||||
stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xz_crc32_init();
|
||||
xz_crc32_init();
|
||||
#ifdef XZ_USE_CRC64
|
||||
xz_crc64_init();
|
||||
xz_crc64_init();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Support up to 64 MiB dictionary. The actually needed memory
|
||||
* is allocated once the headers have been parsed.
|
||||
*/
|
||||
s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
||||
if (s == NULL)
|
||||
{
|
||||
msg = "Memory allocation failed\n";
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
* Support up to 64 MiB dictionary. The actually needed memory
|
||||
* is allocated once the headers have been parsed.
|
||||
*/
|
||||
s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
||||
if (s == NULL)
|
||||
{
|
||||
msg = "Memory allocation failed\n";
|
||||
goto error;
|
||||
}
|
||||
|
||||
b.in = in;
|
||||
b.in_pos = 0;
|
||||
b.in_size = 0;
|
||||
b.out = out;
|
||||
b.out_pos = 0;
|
||||
b.out_size = BUFSIZ;
|
||||
b.in = in;
|
||||
b.in_pos = 0;
|
||||
b.in_size = 0;
|
||||
b.out = out;
|
||||
b.out_pos = 0;
|
||||
b.out_size = BUFSIZ;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (b.in_pos == b.in_size)
|
||||
{
|
||||
b.in_size = fread(in, 1, sizeof(in), stdin);
|
||||
b.in_pos = 0;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (b.in_pos == b.in_size)
|
||||
{
|
||||
b.in_size = fread(in, 1, sizeof(in), stdin);
|
||||
b.in_pos = 0;
|
||||
}
|
||||
|
||||
ret = xz_dec_run(s, &b);
|
||||
ret = xz_dec_run(s, &b);
|
||||
|
||||
if (b.out_pos == sizeof(out))
|
||||
{
|
||||
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos)
|
||||
{
|
||||
msg = "Write error\n";
|
||||
goto error;
|
||||
}
|
||||
if (b.out_pos == sizeof(out))
|
||||
{
|
||||
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos)
|
||||
{
|
||||
msg = "Write error\n";
|
||||
goto error;
|
||||
}
|
||||
|
||||
b.out_pos = 0;
|
||||
}
|
||||
b.out_pos = 0;
|
||||
}
|
||||
|
||||
if (ret == XZ_OK)
|
||||
continue;
|
||||
if (ret == XZ_OK)
|
||||
continue;
|
||||
|
||||
#ifdef XZ_DEC_ANY_CHECK
|
||||
if (ret == XZ_UNSUPPORTED_CHECK)
|
||||
{
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs("Unsupported check; not verifying "
|
||||
"file integrity\n",
|
||||
stderr);
|
||||
continue;
|
||||
}
|
||||
if (ret == XZ_UNSUPPORTED_CHECK)
|
||||
{
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs("Unsupported check; not verifying "
|
||||
"file integrity\n",
|
||||
stderr);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos || fclose(stdout))
|
||||
{
|
||||
msg = "Write error\n";
|
||||
goto error;
|
||||
}
|
||||
if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos || fclose(stdout))
|
||||
{
|
||||
msg = "Write error\n";
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case XZ_STREAM_END:
|
||||
xz_dec_end(s);
|
||||
return 0;
|
||||
switch (ret)
|
||||
{
|
||||
case XZ_STREAM_END:
|
||||
xz_dec_end(s);
|
||||
return 0;
|
||||
|
||||
case XZ_MEM_ERROR:
|
||||
msg = "Memory allocation failed\n";
|
||||
goto error;
|
||||
case XZ_MEM_ERROR:
|
||||
msg = "Memory allocation failed\n";
|
||||
goto error;
|
||||
|
||||
case XZ_MEMLIMIT_ERROR:
|
||||
msg = "Memory usage limit reached\n";
|
||||
goto error;
|
||||
case XZ_MEMLIMIT_ERROR:
|
||||
msg = "Memory usage limit reached\n";
|
||||
goto error;
|
||||
|
||||
case XZ_FORMAT_ERROR:
|
||||
msg = "Not a .xz file\n";
|
||||
goto error;
|
||||
case XZ_FORMAT_ERROR:
|
||||
msg = "Not a .xz file\n";
|
||||
goto error;
|
||||
|
||||
case XZ_OPTIONS_ERROR:
|
||||
msg = "Unsupported options in the .xz headers\n";
|
||||
goto error;
|
||||
case XZ_OPTIONS_ERROR:
|
||||
msg = "Unsupported options in the .xz headers\n";
|
||||
goto error;
|
||||
|
||||
case XZ_DATA_ERROR:
|
||||
case XZ_BUF_ERROR:
|
||||
msg = "File is corrupt\n";
|
||||
goto error;
|
||||
case XZ_DATA_ERROR:
|
||||
case XZ_BUF_ERROR:
|
||||
msg = "File is corrupt\n";
|
||||
goto error;
|
||||
|
||||
default:
|
||||
msg = "Bug!\n";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
default:
|
||||
msg = "Bug!\n";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
xz_dec_end(s);
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs(msg, stderr);
|
||||
return 1;
|
||||
xz_dec_end(s);
|
||||
fputs(argv[0], stderr);
|
||||
fputs(": ", stderr);
|
||||
fputs(msg, stderr);
|
||||
return 1;
|
||||
}
|
||||
|
Reference in New Issue
Block a user