NOISSUE tabs -> spaces

This commit is contained in:
Petr Mrázek
2018-07-15 14:51:05 +02:00
parent 03280cc62e
commit bbb3b3e6f6
577 changed files with 51938 additions and 51938 deletions

View File

@ -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})

View File

@ -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;
};

View File

@ -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)
}

View File

@ -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.
*/

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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";
}
;
};
}

View File

@ -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;
};
}

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();
};

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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, "&amp;");
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, "&amp;");
break;
/* the single quote is a valid URL character
* according to the standard; it needs HTML
* entity escaping too */
case '\'':
HOEDOWN_BUFPUTSL(ob, "&#x27;");
break;
/* the single quote is a valid URL character
* according to the standard; it needs HTML
* entity escaping too */
case '\'':
HOEDOWN_BUFPUTSL(ob, "&#x27;");
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

View File

@ -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 "&apos;" 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 "&apos;" 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[] = { "'", "&#39;", "&#x27;", "&apos;", NULL };
char** p;
static char* single_quote_list[] = { "'", "&#39;", "&#x27;", "&apos;", 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. &apos; or &#39; or &#x27;.
'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. &apos; or &#39; or &#x27;.
'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 &ldquo; or &rdquo; */
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 &ldquo; or &rdquo; */
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, "&rsquo;");
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, "&rsquo;");
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, "&rsquo;");
return 0;
}
}
}
if (((t1 == 'r' && t2 == 'e') ||
(t1 == 'l' && t2 == 'l') ||
(t1 == 'v' && t2 == 'e')) &&
(size == 4 || word_boundary(text[3]))) {
HOEDOWN_BUFPUTSL(ob, "&rsquo;");
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, "&copy;");
return 2;
}
if (t1 == 'c' && t2 == ')') {
HOEDOWN_BUFPUTSL(ob, "&copy;");
return 2;
}
if (t1 == 'r' && t2 == ')') {
HOEDOWN_BUFPUTSL(ob, "&reg;");
return 2;
}
if (t1 == 'r' && t2 == ')') {
HOEDOWN_BUFPUTSL(ob, "&reg;");
return 2;
}
if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') {
HOEDOWN_BUFPUTSL(ob, "&trade;");
return 3;
}
}
if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') {
HOEDOWN_BUFPUTSL(ob, "&trade;");
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, "&mdash;");
return 2;
}
if (size >= 3 && text[1] == '-' && text[2] == '-') {
HOEDOWN_BUFPUTSL(ob, "&mdash;");
return 2;
}
if (size >= 2 && text[1] == '-') {
HOEDOWN_BUFPUTSL(ob, "&ndash;");
return 1;
}
if (size >= 2 && text[1] == '-') {
HOEDOWN_BUFPUTSL(ob, "&ndash;");
return 1;
}
hoedown_buffer_putc(ob, text[0]);
return 0;
hoedown_buffer_putc(ob, text[0]);
return 0;
}
/* Converts &quot; 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, "&quot;", 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, "&quot;", 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, "&#0;", 4) == 0)
return 3;
if (size >= 4 && memcmp(text, "&#0;", 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, "&hellip;");
return 2;
}
if (size >= 3 && text[1] == '.' && text[2] == '.') {
HOEDOWN_BUFPUTSL(ob, "&hellip;");
return 2;
}
if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') {
HOEDOWN_BUFPUTSL(ob, "&hellip;");
return 4;
}
if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') {
HOEDOWN_BUFPUTSL(ob, "&hellip;");
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, "&frac12;");
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, "&frac12;");
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, "&frac14;");
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, "&frac14;");
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, "&frac34;");
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, "&frac34;");
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, "&quot;");
if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote))
HOEDOWN_BUFPUTSL(ob, "&quot;");
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);
}
}
}

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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}
)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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})

View File

@ -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);
}
}

View File

@ -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}")

View File

@ -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)
{
}
}

View File

@ -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;
}

View File

@ -18,5 +18,5 @@ package org.multimc;
public interface Launcher
{
abstract int launch(ParamBucket params);
abstract int launch(ParamBucket params);
}

View File

@ -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>>();
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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()

View File

@ -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;
}

View File

@ -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));
}
}
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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

View File

@ -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);
};

View File

@ -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

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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);
};

View File

@ -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}
)

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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
)

View File

@ -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);

View File

@ -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();

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}
*/
};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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()

View File

@ -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;
};
/**

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
/*

View File

@ -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)

View File

@ -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 */

View File

@ -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;
}