# HG changeset patch # User nemo # Date 1353202232 18000 # Node ID bcebfc477459f3b64c9b0d596f598eebbd0b5cf0 # Parent 39f8ea1a441f3dea093fb71664963d8c30480916# Parent 93e16240f1789e5f3c60de001b85c3bbd0b8e4cb merge... need to remember to update first diff -r 39f8ea1a441f -r bcebfc477459 CMakeLists.txt --- a/CMakeLists.txt Sat Nov 17 20:27:49 2012 -0500 +++ b/CMakeLists.txt Sat Nov 17 20:30:32 2012 -0500 @@ -247,6 +247,10 @@ #main engine add_subdirectory(hedgewars) +# physfs library +add_subdirectory(misc/physfs) +add_subdirectory(misc/physfs/extras) + #Android related build scripts if(ANDROID) #run cmake -DANDROID=1 to enable this @@ -256,7 +260,6 @@ #TODO: when ANDROID, BUILD_ENGINE_LIBRARY should be set if(NOT (BUILD_ENGINE_LIBRARY OR ANDROID)) add_subdirectory(bin) - add_subdirectory(misc/quazip) add_subdirectory(QTfrontend) add_subdirectory(share) add_subdirectory(tools) diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/CMakeLists.txt Sat Nov 17 20:30:32 2012 -0500 @@ -15,16 +15,6 @@ include(${QT_USE_FILE}) endif() -# Check if we need zlib -check_library_exists("${QT_QTCORE_LIBRARY}" inflateInit2_ ${QT_LIBRARY_DIR} QT_PROVIDES_ZLIB_FUNCTIONS) - -if(NOT QT_PROVIDES_ZLIB_FUNCTIONS) - find_package(ZLIB REQUIRED) - - set(HW_LINK_LIBS ${ZLIB_LIBRARIES} ${HW_LINK_LIBS}) -endif() - - # Configure for SDL find_package(SDL REQUIRED) find_package(SDL_mixer REQUIRED) @@ -43,7 +33,8 @@ include_directories(${SDL_INCLUDE_DIR}) include_directories(${SDLMIXER_INCLUDE_DIR}) include_directories(${FFMPEG_INCLUDE_DIR}) -include_directories(${CMAKE_SOURCE_DIR}/misc/quazip) +include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src) +include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/extras) if(UNIX) # HACK: in freebsd cannot find iconv.h included via SDL.h include_directories("/usr/local/include") @@ -176,7 +167,8 @@ set(HW_LINK_LIBS - quazip + physfs + physfsrwops ${QT_LIBRARIES} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY} @@ -200,7 +192,7 @@ if (CROSSAPPLE) - add_dependencies(hedgewars quazip) + else() target_link_libraries(hedgewars ${HW_LINK_LIBS}) endif() diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/campaign.cpp --- a/QTfrontend/campaign.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/campaign.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -56,7 +56,7 @@ QStringList getCampMissionList(QString & campaign) { - QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0); + QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0); campfile.setIniCodec("UTF-8"); unsigned int mNum = campfile.value("MissionNum", 0).toInt(); @@ -77,7 +77,7 @@ QString getCampaignScript(QString campaign, unsigned int mNum) { - QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0); + QSettings campfile("physfs://Missions/Campaign/" + campaign + "/campaign.ini", QSettings::IniFormat, 0); campfile.setIniCodec("UTF-8"); return campfile.value(QString("Mission %1/Script").arg(mNum)).toString(); } diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/hwform.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -122,9 +122,7 @@ , hwnet(0) { // set music track - SDLInteraction::instance().setMusicTrack( - DataManager::instance().findFileForRead("Music/main_theme.ogg") - ); + SDLInteraction::instance().setMusicTrack("/Music/main_theme.ogg"); #ifdef USE_XFIRE xfire_init(); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/main.cpp --- a/QTfrontend/main.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/main.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -33,6 +33,7 @@ #include "newnetclient.h" #include "DataManager.h" +#include "FileEngine.h" #ifdef _WIN32 #include @@ -106,6 +107,8 @@ { HWApplication app(argc, argv); + FileEngineHandler engine(argv[0]); + app.setAttribute(Qt::AA_DontShowIconsInMenus,false); QStringList arguments = app.arguments(); @@ -147,7 +150,7 @@ custom_config = true; } - app.setStyle(new QPlastiqueStyle); + app.setStyle(new QPlastiqueStyle()); QDateTime now = QDateTime::currentDateTime(); srand(now.toTime_t()); @@ -218,21 +221,23 @@ return 1; } - DataManager & dataMgr = DataManager::instance(); + // setup PhysFS + engine.mount(datadir->absolutePath()); + engine.mount(cfgdir->absolutePath() + "/Data"); + engine.mount(cfgdir->absolutePath(), "/config"); + engine.setWriteDir(cfgdir->absolutePath()); + engine.mountPacks(); QTranslator Translator; { - QSettings settings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat); + QSettings settings("physfs://config/hedgewars.ini", QSettings::IniFormat); QString cc = settings.value("misc/locale", QString()).toString(); if(cc.isEmpty()) cc = QLocale::system().name(); // load locale file into translator - Translator.load( - dataMgr.findFileForRead( - QString("Locale/hedgewars_" + cc) - ) - ); + if(!Translator.load(QString("physfs://Locale/hedgewars_%1").arg(cc))) + qWarning("Failed to install translation"); app.installTranslator(&Translator); } @@ -274,7 +279,7 @@ } // load external stylesheet if there is any - QFile extFile(dataMgr.findFileForRead("css/" + fname)); + QFile extFile("physfs://css/" + fname); QFile resFile(":/res/css/" + fname); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/model/GameStyleModel.cpp --- a/QTfrontend/model/GameStyleModel.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/model/GameStyleModel.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -55,8 +55,7 @@ { script = script.remove(".lua", Qt::CaseInsensitive); - QFile scriptCfgFile(DataManager::instance().findFileForRead( - QString("Scripts/Multiplayer/%2.cfg").arg(script))); + QFile scriptCfgFile(QString("physfs://Scripts/Multiplayer/%2.cfg").arg(script)); QString name = script; name = name.replace("_", " "); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/model/HatModel.cpp --- a/QTfrontend/model/HatModel.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/model/HatModel.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -46,9 +46,7 @@ DataManager & dataMgr = DataManager::instance(); - QPixmap hhpix = QPixmap( - dataMgr.findFileForRead("Graphics/Hedgehog/Idle.png") - ).copy(0, 0, 32, 32); + QPixmap hhpix = QPixmap("physfs://Graphics/Hedgehog/Idle.png").copy(0, 0, 32, 32); // my reserved hats QStringList hatsList = dataMgr.entryList( @@ -76,11 +74,9 @@ QString str = hatsList.at(i); str = str.remove(QRegExp("\\.png$")); - QPixmap pix( - dataMgr.findFileForRead( - "Graphics/Hats/" + QString(isReserved?"Reserved/":"") + str + - ".png" - ) + QPixmap pix( + "physfs://Graphics/Hats/" + QString(isReserved?"Reserved/":"") + str + + ".png" ); // rename properly diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/model/MapModel.cpp --- a/QTfrontend/model/MapModel.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/model/MapModel.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -62,10 +62,8 @@ // add mission/static maps to lists foreach (QString map, maps) { - mapCfgFile.setFileName( - datamgr.findFileForRead(QString("Maps/%1/map.cfg").arg(map))); - mapLuaFile.setFileName( - datamgr.findFileForRead(QString("Maps/%1/map.lua").arg(map))); + mapCfgFile.setFileName(QString("physfs://Maps/%1/map.cfg").arg(map)); + mapLuaFile.setFileName(QString("physfs://Maps/%1/map.lua").arg(map)); if (mapCfgFile.open(QFile::ReadOnly)) diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/model/ThemeModel.cpp --- a/QTfrontend/model/ThemeModel.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/model/ThemeModel.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -66,8 +66,7 @@ foreach (QString theme, themes) { // themes without icon are supposed to be hidden - QString iconpath = - datamgr.findFileForRead(QString("Themes/%1/icon.png").arg(theme)); + QString iconpath = QString("physfs://Themes/%1/icon.png").arg(theme); if (!QFile::exists(iconpath)) continue; @@ -79,10 +78,11 @@ // load and set icon QIcon icon(iconpath); + dataset.insert(Qt::DecorationRole, icon); // load and set preview icon - QIcon preview(datamgr.findFileForRead(QString("Themes/%1/icon@2x.png").arg(theme))); + QIcon preview(QString("physfs://Themes/%1/icon@2x.png").arg(theme)); dataset.insert(Qt::UserRole, preview); m_data.append(dataset); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/team.cpp --- a/QTfrontend/team.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/team.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -169,7 +169,7 @@ bool HWTeam::loadFromFile() { - QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt", QSettings::IniFormat, 0); + QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0); teamfile.setIniCodec("UTF-8"); m_name = teamfile.value("Team/Name", m_name).toString(); m_grave = teamfile.value("Team/Grave", "Statue").toString(); @@ -202,7 +202,7 @@ bool HWTeam::fileExists() { - QFile f(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt"); + QFile f(QString("physfs://config/Teams/%1.hwt").arg(m_name)); return f.exists(); } @@ -210,7 +210,7 @@ { if(m_isNetTeam) return false; - QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt"); + QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(m_name)); cfgfile.remove(); return true; } @@ -219,11 +219,11 @@ { if (OldTeamName != m_name) { - QFile cfgfile(cfgdir->absolutePath() + "/Teams/" + OldTeamName + ".hwt"); + QFile cfgfile(QString("physfs://config/Teams/%1.hwt").arg(OldTeamName)); cfgfile.remove(); OldTeamName = m_name; } - QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + m_name + ".hwt", QSettings::IniFormat, 0); + QSettings teamfile(QString("physfs://config/Teams/%1.hwt").arg(m_name), QSettings::IniFormat, 0); teamfile.setIniCodec("UTF-8"); teamfile.setValue("Team/Name", m_name); teamfile.setValue("Team/Grave", m_grave); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/mouseoverfilter.cpp --- a/QTfrontend/ui/mouseoverfilter.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/mouseoverfilter.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -41,8 +41,7 @@ QTabWidget * tab = dynamic_cast(dist); if (HWForm::config->isFrontendSoundEnabled() && (button || textfield || checkbox || droplist || slider || tab)) { - DataManager & dataMgr = DataManager::instance(); - SDLInteraction::instance().playSoundFile(dataMgr.findFileForRead("Sounds/steps.ogg")); + SDLInteraction::instance().playSoundFile("/Sounds/steps.ogg"); } return true; diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/page/pagedata.cpp --- a/QTfrontend/ui/page/pagedata.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/page/pagedata.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -31,9 +31,7 @@ #include "databrowser.h" #include "hwconsts.h" #include "DataManager.h" - -#include "quazip.h" -#include "quazipfile.h" +#include "FileEngine.h" QLayout * PageDataDownload::bodyLayoutDefinition() { @@ -74,7 +72,7 @@ else finalUrl = url; - if(url.path().endsWith(".zip")) + if(url.path().endsWith(".hwp")) { qWarning() << "Download Request" << url.toString(); QString fileName = QFileInfo(url.toString()).fileName(); @@ -128,7 +126,6 @@ if(reply) { - QByteArray fileContents = reply->readAll(); QProgressBar *progressBar = progressBars.value(reply, 0); if(progressBar) @@ -137,7 +134,24 @@ progressBar->deleteLater(); } - extractDataPack(&fileContents); + QDir extractDir(*cfgdir); + extractDir.cd("Data"); + + QString fileName = extractDir.filePath(QFileInfo(reply->url().path()).fileName()); + + QFile out(fileName); + if(!out.open(QFile::WriteOnly)) + { + qWarning() << "out.open():" << out.errorString(); + return ; + } + + out.write(reply->readAll()); + + out.close(); + + // now mount it + FileEngineHandler::mount(fileName); } } @@ -162,83 +176,6 @@ request(QUrl("http://hedgewars.org/content.html")); } -bool PageDataDownload::extractDataPack(QByteArray * buf) -{ - QBuffer buffer; - buffer.setBuffer(buf); - - QuaZip zip; - zip.setIoDevice(&buffer); - if(!zip.open(QuaZip::mdUnzip)) - { - qWarning("testRead(): zip.open(): %d", zip.getZipError()); - return false; - } - - QuaZipFile file(&zip); - - QDir extractDir(*cfgdir); - extractDir.cd("Data"); - - for(bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) - { - if(!file.open(QIODevice::ReadOnly)) - { - qWarning("file.open(): %d", file.getZipError()); - return false; - } - - - QString fileName = file.getActualFileName(); - QString filePath = extractDir.filePath(fileName); - if (fileName.endsWith("/")) - { - QFileInfo fi(filePath); - QDir().mkpath(fi.filePath()); - } - else - { - qDebug() << "Extracting" << filePath; - QFile out(filePath); - if(!out.open(QFile::WriteOnly)) - { - qWarning() << "out.open():" << out.errorString(); - return false; - } - - out.write(file.readAll()); - - out.close(); - - if(file.getZipError() != UNZ_OK) - { - qWarning("file.getFileName(): %d", file.getZipError()); - return false; - } - - if(!file.atEnd()) - { - qWarning("read all but not EOF"); - return false; - } - - m_contentDownloaded = true; - } - - file.close(); - - if(file.getZipError()!=UNZ_OK) - { - qWarning("file.close(): %d", file.getZipError()); - return false; - } - } - - zip.close(); - - return true; -} - void PageDataDownload::onPageLeave() { diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/page/pagedata.h --- a/QTfrontend/ui/page/pagedata.h Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/page/pagedata.h Sat Nov 17 20:30:32 2012 -0500 @@ -48,8 +48,6 @@ bool m_contentDownloaded; ///< true if something was downloaded since last page leave - bool extractDataPack(QByteArray * buf); - private slots: void request(const QUrl &url); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/page/pageeditteam.cpp --- a/QTfrontend/ui/page/pageeditteam.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/page/pageeditteam.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -270,7 +270,7 @@ foreach (QString file, list) { - QPixmap pix(dataMgr.findFileForRead("Graphics/Graves/" + file)); + QPixmap pix("physfs://Graphics/Graves/" + file); if ((pix.height() > 32) || pix.width() > 32) pix = pix.copy(0, 0, 32, 32); QIcon icon(pix); @@ -297,7 +297,7 @@ list.removeAt(idx); // add the default flag - QPixmap hwFlag(dataMgr.findFileForRead("Graphics/Flags/hedgewars.png")); + QPixmap hwFlag("physfs://Graphics/Flags/hedgewars.png"); CBFlag->addItem(QIcon(hwFlag.copy(0, 0, 22, 15)), "Hedgewars", "hedgewars"); // add seperator after @@ -308,7 +308,7 @@ // add all country flags foreach (const QString & file, list) { - QIcon icon(QPixmap(dataMgr.findFileForRead("Graphics/Flags/" + file))); + QIcon icon(QPixmap("physfs://Graphics/Flags/" + file)); QString flag = QString(file).remove(pngSuffix); @@ -337,8 +337,7 @@ void PageEditTeam::CBFort_activated(const QString & fortname) { - DataManager & dataMgr = DataManager::instance(); - QPixmap pix(dataMgr.findFileForRead("Forts/" + fortname + "L.png")); + QPixmap pix("physfs://Forts/" + fortname + "L.png"); FortPreview->setPixmap(pix); } @@ -360,10 +359,8 @@ ); if (!list.isEmpty()) - SDLInteraction::instance().playSoundFile( - dataMgr.findFileForRead(voiceDir + "/" + - list[rand() % list.size()]) - ); + SDLInteraction::instance().playSoundFile("physfs://" + voiceDir + "/" + + list[rand() % list.size()]); } void PageEditTeam::createTeam(const QString & name, const QString & playerHash) diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/page/pagetraining.cpp --- a/QTfrontend/ui/page/pagetraining.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/page/pagetraining.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -125,17 +125,15 @@ if (loc.isEmpty()) loc = QLocale::system().name(); - QString infoFile = dataMgr.findFileForRead( - QString("Locale/missions_" + loc + ".txt")); + QString infoFile = QString("physfs://Locale/missions_" + loc + ".txt"); // if file is non-existant try with language only if (!QFile::exists(infoFile)) - infoFile = dataMgr.findFileForRead(QString( - "Locale/missions_" + loc.remove(QRegExp("_.*$")) + ".txt")); + infoFile = QString("physfs://Locale/missions_" + loc.remove(QRegExp("_.*$")) + ".txt"); // fallback if file for current locale is non-existant if (!QFile::exists(infoFile)) - infoFile = dataMgr.findFileForRead(QString("Locale/missions_en.txt")); + infoFile = QString("physfs://Locale/missions_en.txt"); // preload mission info for current locale @@ -186,15 +184,12 @@ void PageTraining::updateInfo() { - DataManager & dataMgr = DataManager::instance(); - if (lstMissions->currentItem()) { // TODO also use .pngs in userdata folder - QString thumbFile = dataMgr.findFileForRead( - "Graphics/Missions/Training/" + + QString thumbFile = "physfs://Graphics/Missions/Training/" + lstMissions->currentItem()->data(Qt::UserRole).toString() + - "@2x.png"); + "@2x.png"; if (QFile::exists(thumbFile)) btnPreview->setIcon(QIcon(thumbFile)); diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/widget/chatwidget.cpp --- a/QTfrontend/ui/widget/chatwidget.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/widget/chatwidget.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -64,7 +64,7 @@ if (orgStyleSheet.isEmpty()) { // load external stylesheet if there is any - QFile extFile(DataManager::instance().findFileForRead("css/chat.css")); + QFile extFile("physfs://css/chat.css"); QFile resFile(":/res/css/chat.css"); @@ -194,12 +194,10 @@ foreach (QString vp, vpList) { - m_helloSounds.append(DataManager::instance().findFileForRead( - QString("Sounds/voices/%1/Hello.ogg").arg(vp))); + m_helloSounds.append(QString("physfs://Sounds/voices/%1/Hello.ogg").arg(vp)); } - m_hilightSound = DataManager::instance().findFileForRead( - "Sounds/beep.ogg"); + m_hilightSound = "physfs://Sounds/beep.ogg"; } @@ -762,8 +760,7 @@ void HWChatWidget::saveStyleSheet() { - QString dest = - DataManager::instance().findFileForWrite("css/chat.css"); + QString dest = "physfs://css/chat.css"; QFile file(dest); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/widget/mapContainer.cpp --- a/QTfrontend/ui/widget/mapContainer.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/widget/mapContainer.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -606,10 +606,7 @@ break; default: QPixmap mapImage; - bool success = mapImage.load( - DataManager::instance().findFileForRead( - "Maps/" + m_mapInfo.name + "/preview.png") - ); + bool success = mapImage.load("physfs://Maps/" + m_mapInfo.name + "/preview.png"); if(!success) { diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/ui/widget/qpushbuttonwithsound.cpp --- a/QTfrontend/ui/widget/qpushbuttonwithsound.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/ui/widget/qpushbuttonwithsound.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -36,8 +36,6 @@ if ( !isSoundEnabled || !HWForm::config->isFrontendSoundEnabled()) return; - DataManager & dataMgr = DataManager::instance(); - if (this->isEnabled()) - SDLInteraction::instance().playSoundFile(dataMgr.findFileForRead("Sounds/roperelease.ogg")); + SDLInteraction::instance().playSoundFile("/Sounds/roperelease.ogg"); } diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/util/DataManager.cpp --- a/QTfrontend/util/DataManager.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/util/DataManager.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -39,12 +39,6 @@ DataManager::DataManager() { - m_userData = new QDir(cfgdir->absolutePath()); - if (!m_userData->cd("Data")) - m_userData = NULL; - - m_defaultData = new QDir(datadir->absolutePath()); - m_hatModel = NULL; m_mapModel = NULL; m_themeModel = NULL; @@ -66,20 +60,8 @@ const QStringList & nameFilters ) const { - QStringList result; - - if (m_userData != NULL) - { - QDir tmpDir(*m_userData); - if (tmpDir.cd(subDirectory)) - result.append(tmpDir.entryList(nameFilters, filters)); - } - - QDir tmpDir(*m_defaultData); - if (tmpDir.cd(subDirectory)) - result.append(tmpDir.entryList(nameFilters, filters)); - - result.removeDuplicates(); + QDir tmpDir(QString("physfs://%1").arg(subDirectory)); + QStringList result = tmpDir.entryList(nameFilters, filters); // sort case-insensitive QMap sortedFileNames; @@ -92,40 +74,6 @@ return result; } - -QString DataManager::findFileForRead( - const QString & relativeDataFilePath) const -{ - QString path; - - if (m_userData != NULL) - path = m_userData->absolutePath()+"/"+relativeDataFilePath; - - if ((!path.isEmpty()) && (!QFile::exists(path))) - path = m_defaultData->absolutePath()+"/"+relativeDataFilePath; - - return path; -} - - -QString DataManager::findFileForWrite( - const QString & relativeDataFilePath) const -{ - if (m_userData != NULL) - { - QString path = m_userData->absolutePath()+"/"+relativeDataFilePath; - - // create folders if needed - QDir tmp; - tmp.mkpath(QFileInfo(path).absolutePath()); - - return path; - } - - - return ""; -} - GameStyleModel * DataManager::gameStyleModel() { if (m_gameStyleModel == NULL) { diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/util/DataManager.h --- a/QTfrontend/util/DataManager.h Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/util/DataManager.h Sat Nov 17 20:30:32 2012 -0500 @@ -70,28 +70,6 @@ ) const; /** - * @brief Returns the path for the desires data file. - * - * Use this method if you want to read an existing data file. - * - * @param relativeDataFilePath relative path of the data file. - * @return real path to the file. - */ - QString findFileForRead(const QString & relativeDataFilePath) const; - - - /** - * @brief Returns the path for the data file that is to be written. - * - * Use this method if you want to create or write into a data file. - * - * @param relativeDataFilePath relative path of data file write path. - * @return destination of path data file. - */ - QString findFileForWrite(const QString & relativeDataFilePath) const; - - - /** * @brief Returns pointer to a model of available game styles. * * The model is updated automatically on data reload. @@ -152,9 +130,6 @@ */ DataManager(); - QDir * m_defaultData; ///< directory of the installed data - QDir * m_userData; ///< directory of custom data in the user's directory - GameStyleModel * m_gameStyleModel; ///< game style model instance HatModel * m_hatModel; ///< hat model instance MapModel * m_mapModel; ///< map model instance diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/util/FileEngine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/util/FileEngine.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,306 @@ +/* borrowed from https://github.com/skhaz/qt-physfs-wrapper + * TODO: add copyright header, determine license + */ + + +#include "hwpacksmounter.h" +#include "FileEngine.h" + + +const QString FileEngineHandler::scheme = "physfs:/"; + +FileEngine::FileEngine(const QString& filename) +: _handler(NULL) +, _flags(0) +{ + setFileName(filename); +} + +FileEngine::~FileEngine() +{ + close(); +} + +bool FileEngine::open(QIODevice::OpenMode openMode) +{ + close(); + + if (openMode & QIODevice::WriteOnly) { + _handler = PHYSFS_openWrite(_filename.toUtf8().constData()); + _flags = QAbstractFileEngine::WriteOwnerPerm | QAbstractFileEngine::WriteUserPerm | QAbstractFileEngine::FileType; + } + + else if (openMode & QIODevice::ReadOnly) { + _handler = PHYSFS_openRead(_filename.toUtf8().constData()); + } + + else if (openMode & QIODevice::Append) { + _handler = PHYSFS_openAppend(_filename.toUtf8().constData()); + } + + else { + qWarning("Bad file open mode: %d", (int)openMode); + } + + if (!_handler) { + qWarning("Failed to open %s, reason: %s", _filename.toUtf8().constData(), PHYSFS_getLastError()); + return false; + } + + return true; +} + +bool FileEngine::close() +{ + if (isOpened()) { + int result = PHYSFS_close(_handler); + _handler = NULL; + return result != 0; + } + + return true; +} + +bool FileEngine::flush() +{ + return PHYSFS_flush(_handler) != 0; +} + +qint64 FileEngine::size() const +{ + return _size; +} + +qint64 FileEngine::pos() const +{ + return PHYSFS_tell(_handler); +} + +bool FileEngine::seek(qint64 pos) +{ + return PHYSFS_seek(_handler, pos) != 0; +} + +bool FileEngine::isSequential() const +{ + return false; +} + +bool FileEngine::remove() +{ + return PHYSFS_delete(_filename.toUtf8().constData()) != 0; +} + +bool FileEngine::mkdir(const QString &dirName, bool createParentDirectories) const +{ + Q_UNUSED(createParentDirectories); + return PHYSFS_mkdir(dirName.toUtf8().constData()) != 0; +} + +bool FileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const +{ + Q_UNUSED(recurseParentDirectories); + return PHYSFS_delete(dirName.toUtf8().constData()) != 0; +} + +bool FileEngine::caseSensitive() const +{ + return true; +} + +bool FileEngine::isRelativePath() const +{ + return true; +} + +QAbstractFileEngineIterator * FileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) +{ + return new FileEngineIterator(filters, filterNames, entryList(filters, filterNames)); +} + +QStringList FileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const +{ + Q_UNUSED(filters); + + QString file; + QStringList result; + char **files = PHYSFS_enumerateFiles(_filename.toUtf8().constData()); + + for (char **i = files; *i != NULL; i++) { + file = QString::fromUtf8(*i); + + if (filterNames.isEmpty() || QDir::match(filterNames, file)) { + result << file; + } + } + + PHYSFS_freeList(files); + + return result; +} + +QAbstractFileEngine::FileFlags FileEngine::fileFlags(FileFlags type) const +{ + return type & _flags; +} + +QString FileEngine::fileName(FileName file) const +{ + if (file == QAbstractFileEngine::AbsolutePathName) + return PHYSFS_getWriteDir(); + + return QString("physfs://%1").arg(_filename); +} + +QDateTime FileEngine::fileTime(FileTime time) const +{ + + switch (time) + { + case QAbstractFileEngine::ModificationTime: + default: + return _datetime; + break; + }; +} + +void FileEngine::setFileName(const QString &file) +{ + if(file.startsWith(FileEngineHandler::scheme)) + _filename = file.mid(FileEngineHandler::scheme.size()); + else + _filename = file; + + PHYSFS_Stat stat; + if (PHYSFS_stat(_filename.toUtf8().constData(), &stat) != 0) { + _size = stat.filesize; + _datetime = QDateTime::fromTime_t(stat.modtime); +// _flags |= QAbstractFileEngine::WriteUserPerm; + _flags |= QAbstractFileEngine::ReadUserPerm; + _flags |= QAbstractFileEngine::ExistsFlag; + + switch (stat.filetype) + { + case PHYSFS_FILETYPE_REGULAR: + _flags |= QAbstractFileEngine::FileType; + break; + + case PHYSFS_FILETYPE_DIRECTORY: + _flags |= QAbstractFileEngine::DirectoryType; + break; + case PHYSFS_FILETYPE_SYMLINK: + _flags |= QAbstractFileEngine::LinkType; + break; + default: ; + } + } +} + +bool FileEngine::atEnd() const +{ + return PHYSFS_eof(_handler) != 0; +} + +qint64 FileEngine::read(char *data, qint64 maxlen) +{ + return PHYSFS_readBytes(_handler, data, maxlen); +} + +qint64 FileEngine::write(const char *data, qint64 len) +{ + return PHYSFS_writeBytes(_handler, data, len); +} + +bool FileEngine::isOpened() const +{ + return _handler != NULL; +} + +QFile::FileError FileEngine::error() const +{ + return QFile::UnspecifiedError; +} + +QString FileEngine::errorString() const +{ + return PHYSFS_getLastError(); +} + +bool FileEngine::supportsExtension(Extension extension) const +{ + return extension == QAbstractFileEngine::AtEndExtension; +} + + + +FileEngineHandler::FileEngineHandler(char *argv0) +{ + PHYSFS_init(argv0); +} + +FileEngineHandler::~FileEngineHandler() +{ + PHYSFS_deinit(); +} + +QAbstractFileEngine* FileEngineHandler::create(const QString &filename) const +{ + if (filename.startsWith(scheme)) + return new FileEngine(filename.mid(scheme.size())); + else + return NULL; +} + +void FileEngineHandler::mount(const QString &path) +{ + PHYSFS_mount(path.toUtf8().constData(), NULL, 1); +} + +void FileEngineHandler::mount(const QString & path, const QString & mountPoint) +{ + PHYSFS_mount(path.toUtf8().constData(), mountPoint.toUtf8().constData(), 1); +} + +void FileEngineHandler::setWriteDir(const QString &path) +{ + PHYSFS_setWriteDir(path.toUtf8().constData()); +} + +void FileEngineHandler::mountPacks() +{ + hedgewarsMountPackages(); +} + + +FileEngineIterator::FileEngineIterator(QDir::Filters filters, const QStringList &nameFilters, const QStringList &entries) + : QAbstractFileEngineIterator(filters, nameFilters) +{ + m_entries = entries; + + /* heck.. docs are unclear on this + * QDirIterator puts iterator before first entry + * but QAbstractFileEngineIterator example puts iterator on first entry + * though QDirIterator approach seems to be the right one + */ + + m_index = -1; +} + +bool FileEngineIterator::hasNext() const +{ + return m_index < m_entries.size() - 1; +} + +QString FileEngineIterator::next() +{ + if (!hasNext()) + return QString(); + + ++m_index; + return currentFilePath(); +} + +QString FileEngineIterator::currentFileName() const +{ + return m_entries.at(m_index); +} diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/util/FileEngine.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/util/FileEngine.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,88 @@ +#ifndef _FileEngine_h +#define _FileEngine_h + +#include +#include +#include +#include + +#include "physfs.h" + + + +class FileEngine : public QAbstractFileEngine +{ + public: + FileEngine(const QString& filename); + + virtual ~FileEngine(); + + virtual bool open(QIODevice::OpenMode openMode); + virtual bool close(); + virtual bool flush(); + virtual qint64 size() const; + virtual qint64 pos() const; + virtual bool seek(qint64 pos); + virtual bool isSequential() const; + virtual bool remove(); + virtual bool mkdir(const QString &dirName, bool createParentDirectories) const; + virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const; + virtual bool caseSensitive() const; + virtual bool isRelativePath() const; + QAbstractFileEngineIterator *beginEntryList(QDir::Filters filters, const QStringList & filterNames); + virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const; + virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const; + virtual QString fileName(FileName file=DefaultName) const; + virtual QDateTime fileTime(FileTime time) const; + virtual void setFileName(const QString &file); + bool atEnd() const; + + virtual qint64 read(char *data, qint64 maxlen); + virtual qint64 write(const char *data, qint64 len); + + bool isOpened() const; + + QFile::FileError error() const; + QString errorString() const; + + virtual bool supportsExtension(Extension extension) const; + + private: + PHYSFS_file *_handler; + qint64 _size; + FileFlags _flags; + QString _filename; + QDateTime _datetime; +}; + +class FileEngineHandler : public QAbstractFileEngineHandler +{ + public: + FileEngineHandler(char * argv0); + ~FileEngineHandler(); + + QAbstractFileEngine *create(const QString &filename) const; + + static void mount(const QString & path); + static void mount(const QString & path, const QString & mountPoint); + static void setWriteDir(const QString & path); + static void mountPacks(); + +// private: + static const QString scheme; +}; + +class FileEngineIterator : public QAbstractFileEngineIterator +{ +public: + FileEngineIterator(QDir::Filters filters, const QStringList & nameFilters, const QStringList & entries); + + bool hasNext() const; + QString next(); + QString currentFileName() const; +private: + QStringList m_entries; + int m_index; +}; + +#endif diff -r 39f8ea1a441f -r bcebfc477459 QTfrontend/util/namegen.cpp --- a/QTfrontend/util/namegen.cpp Sat Nov 17 20:27:49 2012 -0500 +++ b/QTfrontend/util/namegen.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -125,8 +125,7 @@ QStringList list; // find .txt to load the names from - QFile * file = new QFile(DataManager::instance().findFileForRead(QString( - "Names/%1.txt").arg(filename))); + QFile * file = new QFile(QString("physfs://Names/%1.txt").arg(filename)); if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -154,8 +153,7 @@ QStringList list; // find .cfg to load the dicts from - QFile * file = new QFile(DataManager::instance().findFileForRead(QString( - "Names/%1.cfg").arg(hatname))); + QFile * file = new QFile(QString("physfs://Names/%1.cfg").arg(hatname)); if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -183,8 +181,7 @@ typesAvailable = false; // find .ini to load the names from - QFile * file = new QFile( - DataManager::instance().findFileForRead(QString("Names/types.ini"))); + QFile * file = new QFile(QString("physfs://Names/types.ini")); if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text)) diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/CMakeLists.txt Sat Nov 17 20:30:32 2012 -0500 @@ -54,6 +54,7 @@ uLocale.pas uMisc.pas uMobile.pas + uPhysFSLayer.pas uRandom.pas uRender.pas uRenderUtils.pas @@ -99,6 +100,9 @@ endif (APPLE) endif(BUILD_ENGINE_LIBRARY) +# doesn't work for some reason (doesn't find symbols) +#set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/libphysfs.a" ${pascal_flags}) + IF(FPC) set(fpc_executable ${FPC}) ELSE() @@ -269,6 +273,10 @@ add_dependencies(${engine_output_name} lua) endif() +# compile physfs before engine +add_dependencies(${engine_output_name} physfs) +add_dependencies(${engine_output_name} physfsrwops) + #when ffmpeg/libav is found we need to compile it before engine #TODO: convert avwrapper to .pas unit so we can skip this step if(${FFMPEG_FOUND}) diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/SDLh.pas Sat Nov 17 20:30:32 2012 -0500 @@ -1004,7 +1004,7 @@ function TTF_RenderUTF8_Blended(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; function TTF_RenderUTF8_Shaded(font: PTTF_Font; const text: PChar; fg, bg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; -function TTF_OpenFont(const filename: PChar; size: LongInt): PTTF_Font; cdecl; external SDL_TTFLibName; +function TTF_OpenFontRW(src: PSDL_RWops; freesrc: LongBool; size: LongInt): PTTF_Font; cdecl; external SDL_TTFLibName; procedure TTF_SetFontStyle(font: PTTF_Font; style: LongInt); cdecl; external SDL_TTFLibName; (* SDL_mixer *) @@ -1024,7 +1024,7 @@ procedure Mix_FreeMusic(music: PMixMusic); cdecl; external SDL_MixerLibName; function Mix_LoadWAV_RW(src: PSDL_RWops; freesrc: LongInt): PMixChunk; cdecl; external SDL_MixerLibName; -function Mix_LoadMUS(const filename: PChar): PMixMusic; cdecl; external SDL_MixerLibName; +function Mix_LoadMUS_RW(src: PSDL_RWops): PMixMusic; cdecl; external SDL_MixerLibName; function Mix_Playing(channel: LongInt): LongInt; cdecl; external SDL_MixerLibName; function Mix_PlayingMusic: LongInt; cdecl; external SDL_MixerLibName; @@ -1048,9 +1048,9 @@ procedure IMG_Quit; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF} function IMG_Load(const _file: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName; -function IMG_Load_RW(rwop: PSDL_RWops; freesrc: LongInt): PSDL_Surface; cdecl; external SDL_ImageLibName; +function IMG_Load_RW(rwop: PSDL_RWops; freesrc: LongBool): PSDL_Surface; cdecl; external SDL_ImageLibName; function IMG_LoadPNG_RW(rwop: PSDL_RWops): PSDL_Surface; cdecl; external SDL_ImageLibName; -function IMG_LoadTyped_RW(rwop: PSDL_RWops; freesrc: LongInt; type_: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName; +function IMG_LoadTyped_RW(rwop: PSDL_RWops; freesrc: LongBool; type_: PChar): PSDL_Surface; cdecl; external SDL_ImageLibName; (* SDL_net *) function SDLNet_Init: LongInt; cdecl; external SDL_NetLibName; diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/hwengine.pas Sat Nov 17 20:30:32 2012 -0500 @@ -29,9 +29,10 @@ program hwengine; {$ENDIF} -uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler, - uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions, - SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted +uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler + , uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uAILandMarks, uLandTexture, uCollisions + , SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted + , uPhysFSLayer {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF} {$IFDEF USE_TOUCH_INTERFACE}, uTouch {$ENDIF} {$IFDEF ANDROID}, GLUnit{$ENDIF} @@ -343,16 +344,6 @@ for i:= 0 to ParamCount do AddFileLog(inttostr(i) + ': ' + ParamStr(i)); - for p:= Succ(Low(TPathType)) to High(TPathType) do - if (p <> ptMapCurrent) and (p <> ptData) then - UserPathz[p]:= UserPathPrefix + '/Data/' + Pathz[p]; - - UserPathz[ptData]:= UserPathPrefix + '/Data'; - - for p:= Succ(Low(TPathType)) to High(TPathType) do - if p <> ptMapCurrent then - Pathz[p]:= PathPrefix + '/' + Pathz[p]; - WriteToConsole('Init SDL... '); if not cOnlyStats then SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true); WriteLnToConsole(msgOK); @@ -381,18 +372,15 @@ InitKbdKeyTable(); AddProgress(); - LoadLocale(UserPathz[ptLocale] + '/en.txt'); // Do an initial load with english - LoadLocale(Pathz[ptLocale] + '/en.txt'); // Do an initial load with english + LoadLocale(cPathz[ptLocale] + '/en.txt'); // Do an initial load with english if cLocaleFName <> 'en.txt' then begin // Try two letter locale first before trying specific locale overrides - if (Length(cLocale) > 3) and (Copy(cLocale,1,2) <> 'en') then + if (Length(cLocale) > 3) and (Copy(cLocale, 1, 2) <> 'en') then begin - LoadLocale(UserPathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt'); - LoadLocale(Pathz[ptLocale] + '/' + Copy(cLocale,1,2)+'.txt') + LoadLocale(cPathz[ptLocale] + '/' + Copy(cLocale, 1, 2) + '.txt') end; - LoadLocale(UserPathz[ptLocale] + '/' + cLocaleFName); - LoadLocale(Pathz[ptLocale] + '/' + cLocaleFName) + LoadLocale(cPathz[ptLocale] + '/' + cLocaleFName) end else cLocale := 'en'; @@ -459,6 +447,7 @@ if complete then begin + uPhysFSLayer.initModule; {$IFDEF ANDROID}GLUnit.initModule;{$ENDIF} {$IFDEF USE_TOUCH_INTERFACE}uTouch.initModule;{$ENDIF} {$IFDEF USE_VIDEO_RECORDING}uVideoRec.initModule;{$ENDIF} //stub @@ -510,6 +499,7 @@ {$IFDEF USE_VIDEO_RECORDING}uVideoRec.freeModule;{$ENDIF} {$IFDEF USE_TOUCH_INTERFACE}uTouch.freeModule;{$ENDIF} //stub {$IFDEF ANDROID}GLUnit.freeModule;{$ENDIF} + uPhysFSLayer.freeModule; end; uIO.freeModule; diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uCommandHandlers.pas Sat Nov 17 20:30:32 2012 -0500 @@ -548,15 +548,9 @@ if isDeveloperMode then begin if s = '' then - begin - UserPathz[ptMapCurrent]:= s; - Pathz[ptMapCurrent]:= s; - end + cPathz[ptMapCurrent]:= s else - begin - UserPathz[ptMapCurrent]:= UserPathz[ptMaps] + '/' + s; - Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s; - end; + cPathz[ptMapCurrent]:= cPathz[ptMaps] + '/' + s; InitStepsFlags:= InitStepsFlags or cifMap end; cMapName:= s; @@ -567,8 +561,7 @@ begin if isDeveloperMode then begin - UserPathz[ptCurrTheme]:= UserPathz[ptThemes] + '/' + s; - Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s; + cPathz[ptCurrTheme]:= cPathz[ptThemes] + '/' + s; Theme:= s; InitStepsFlags:= InitStepsFlags or cifTheme end diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uLand.pas --- a/hedgewars/uLand.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uLand.pas Sat Nov 17 20:30:32 2012 -0500 @@ -426,10 +426,8 @@ var f: textfile; s: shortstring; begin -// unC0Rr - should this be passed from the GUI? I am not sure which layer does what -s:= UserPathz[ptMapCurrent] + '/map.cfg'; -if not FileExists(s) then - s:= Pathz[ptMapCurrent] + '/map.cfg'; +s:= cPathz[ptMapCurrent] + '/map.cfg'; + WriteLnToConsole('Fetching map HH limit'); {$I-} Assign(f, s); @@ -437,7 +435,7 @@ Reset(f); if IOResult <> 0 then begin - s:= Pathz[ptMissionMaps] + '/' + ExtractFileName(Pathz[ptMapCurrent]) + '/map.cfg'; + s:= cPathz[ptMissionMaps] + '/' + ExtractFileName(cPathz[ptMapCurrent]) + '/map.cfg'; Assign(f, s); Reset(f); end; @@ -459,7 +457,7 @@ tmpsurf:= LoadDataImage(ptMapCurrent, 'mask', ifAlpha or ifTransparent or ifIgnoreCaps); if tmpsurf = nil then begin - mapName:= ExtractFileName(Pathz[ptMapCurrent]); + mapName:= ExtractFileName(cPathz[ptMapCurrent]); tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); end; @@ -533,7 +531,7 @@ tmpsurf:= LoadDataImage(ptMapCurrent, 'map', ifAlpha or ifTransparent or ifIgnoreCaps); if tmpsurf = nil then begin - mapName:= ExtractFileName(Pathz[ptMapCurrent]); + mapName:= ExtractFileName(cPathz[ptMapCurrent]); tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); end; // (bare) Sanity check. Considering possible LongInt comparisons as well as just how much system memoery it would take @@ -581,7 +579,7 @@ procedure GenMap; var x, y, w, c: Longword; - usermap, usermask, map, mask: shortstring; + map, mask: shortstring; maskOnly: boolean; begin hasBorder:= false; @@ -594,14 +592,11 @@ // FillChar(Land,SizeOf(TCollisionArray),0);*) if (GameFlags and gfForts) = 0 then - if Pathz[ptMapCurrent] <> '' then + if cPathz[ptMapCurrent] <> '' then begin - usermap:= UserPathz[ptMapCurrent] + '/map.png'; - usermask:= UserPathz[ptMapCurrent] + '/mask.png'; - map:= Pathz[ptMapCurrent] + '/map.png'; - mask:= Pathz[ptMapCurrent] + '/mask.png'; - if (not(FileExists(usermap)) and FileExists(usermask)) or - (not(FileExists(map)) and FileExists(mask)) then + map:= cPathz[ptMapCurrent] + '/map.png'; + mask:= cPathz[ptMapCurrent] + '/mask.png'; + if (not(FileExists(map)) and FileExists(mask)) then begin maskOnly:= true; LoadMask; @@ -696,7 +691,7 @@ if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false; -if (GameFlags and gfForts = 0) and (maskOnly or (Pathz[ptMapCurrent] = '')) then +if (GameFlags and gfForts = 0) and (maskOnly or (cPathz[ptMapCurrent] = '')) then AddObjects else diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uLandObjects.pas --- a/hedgewars/uLandObjects.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uLandObjects.pas Sat Nov 17 20:30:32 2012 -0500 @@ -30,8 +30,9 @@ procedure AddOnLandObjects(Surface: PSDL_Surface); implementation -uses uStore, uConsts, uConsole, uRandom, uSound, GLunit, - uTypes, uVariables, uUtils, uDebug, SysUtils; +uses uStore, uConsts, uConsole, uRandom, uSound, GLunit + , uTypes, uVariables, uUtils, uDebug, SysUtils + , uPhysFSLayer; const MaxRects = 512; MAXOBJECTRECTS = 16; @@ -399,7 +400,7 @@ procedure ReadThemeInfo(var ThemeObjects: TThemeObjects; var SprayObjects: TSprayObjects); var s, key: shortstring; - f: textfile; + f: PFSFile; i: LongInt; ii, t: Longword; c2: TSDL_Color; @@ -429,21 +430,17 @@ end end; -s:= UserPathz[ptCurrTheme] + '/' + cThemeCFGFilename; -if not FileExists(s) then - s:= Pathz[ptCurrTheme] + '/' + cThemeCFGFilename; +s:= cPathz[ptCurrTheme] + '/' + cThemeCFGFilename; WriteLnToConsole('Reading objects info...'); -Assign(f, s); -{$I-} -filemode:= 0; // readonly -Reset(f); +f:= pfsOpenRead(s); +TryDo(f <> nil, 'Bad data or cannot access file ' + cThemeCFGFilename, true); ThemeObjects.Count:= 0; SprayObjects.Count:= 0; -while not eof(f) do +while not pfsEOF(f) do begin - Readln(f, s); + pfsReadLn(f, s); if Length(s) = 0 then continue; if s[1] = ';' then @@ -738,9 +735,7 @@ end end; -Close(f); -{$I+} -TryDo(IOResult = 0, 'Bad data or cannot access file ' + cThemeCFGFilename, true); +pfsClose(f); AddProgress; end; diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uLocale.pas --- a/hedgewars/uLocale.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uLocale.pas Sat Nov 17 20:30:32 2012 -0500 @@ -34,14 +34,14 @@ {$ENDIF} implementation -uses uRandom, uUtils, uVariables, uDebug; +uses uRandom, uUtils, uVariables, uDebug, uPhysFSLayer; var trevt: array[TEventId] of array [0..Pred(MAX_EVENT_STRINGS)] of ansistring; trevt_n: array[TEventId] of integer; procedure LoadLocale(FileName: shortstring); -var s: ansistring; - f: textfile; +var s: shortstring; + f: pfsFile; a, b, c: LongInt; first: array[TEventId] of boolean; e: TEventId; @@ -51,18 +51,14 @@ for e:= Low(TEventId) to High(TEventId) do first[e]:= true; -{$I-} // iochecks off -Assign(f, FileName); -filemode:= 0; // readonly -Reset(f); -if IOResult = 0 then - loaded:= true; -TryDo(loaded, 'Cannot load locale "' + FileName + '"', false); -if loaded then +f:= pfsOpenRead(FileName); +TryDo(f <> nil, 'Cannot load locale "' + FileName + '"', false); + +if f <> nil then begin - while not eof(f) do + while not pfsEof(f) do begin - readln(f, s); + pfsReadLn(f, s); if Length(s) = 0 then continue; if (s[1] < '0') or (s[1] > '9') then @@ -99,9 +95,8 @@ trgoal[TGoalStrId(b)]:= s; end; end; - Close(f); + pfsClose(f); end; -{$I+} end; function GetEventString(e: TEventId): ansistring; diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uPhysFSLayer.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uPhysFSLayer.pas Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,117 @@ +unit uPhysFSLayer; + +{$LINKLIB ../bin/libphysfs.a} +{$LINKLIB ../bin/libphysfsrwops.a} + +interface +uses SDLh; + +procedure initModule; +procedure freeModule; + +type PFSFile = pointer; + +function rwopsOpenRead(fname: shortstring): PSDL_RWops; +function rwopsOpenWrite(fname: shortstring): PSDL_RWops; + +function pfsOpenRead(fname: shortstring): PFSFile; +function pfsClose(f: PFSFile): boolean; + +procedure pfsReadLn(f: PFSFile; var s: shortstring); +function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64; +function pfsEOF(f: PFSFile): boolean; + +function pfsExists(fname: shortstring): boolean; + +implementation +uses uUtils, uVariables; + +function PHYSFS_init(argv0: PChar) : LongInt; cdecl; external; +function PHYSFS_deinit() : LongInt; cdecl; external; +function PHYSFSRWOPS_openRead(fname: PChar): PSDL_RWops; cdecl; external; +function PHYSFSRWOPS_openWrite(fname: PChar): PSDL_RWops; cdecl; external; + +function PHYSFS_mount(newDir, mountPoint: PChar; appendToPath: LongBool) : LongInt; cdecl; external; +function PHYSFS_openRead(fname: PChar): PFSFile; cdecl; external; +function PHYSFS_eof(f: PFSFile): LongBool; cdecl; external; +function PHYSFS_readBytes(f: PFSFile; buffer: pointer; len: Int64): Int64; cdecl; external; +function PHYSFS_close(f: PFSFile): LongBool; cdecl; external; +function PHYSFS_exists(fname: PChar): LongBool; cdecl; external; + +procedure hedgewarsMountPackages(); cdecl; external; + +function rwopsOpenRead(fname: shortstring): PSDL_RWops; +begin + exit(PHYSFSRWOPS_openRead(Str2PChar(fname))); +end; + +function rwopsOpenWrite(fname: shortstring): PSDL_RWops; +begin + exit(PHYSFSRWOPS_openWrite(Str2PChar(fname))); +end; + +function pfsOpenRead(fname: shortstring): PFSFile; +begin + exit(PHYSFS_openRead(Str2PChar(fname))); +end; + +function pfsEOF(f: PFSFile): boolean; +begin + exit(PHYSFS_eof(f)) +end; + +function pfsClose(f: PFSFile): boolean; +begin + exit(PHYSFS_close(f)) +end; + +function pfsExists(fname: shortstring): boolean; +begin + exit(PHYSFS_exists(Str2PChar(fname))) +end; + + +procedure pfsReadLn(f: PFSFile; var s: shortstring); +var c: char; +begin +s[0]:= #0; + +while (PHYSFS_readBytes(f, @c, 1) = 1) and (c <> #10) do + if (c <> #13) and (s[0] < #255) then + begin + inc(s[0]); + s[byte(s[0])]:= c + end +end; + +function pfsBlockRead(f: PFSFile; buf: pointer; size: Int64): Int64; +var r: Int64; +begin + r:= PHYSFS_readBytes(f, buf, size); + + if r <= 0 then + pfsBlockRead:= 0 + else + pfsBlockRead:= r +end; + +procedure initModule; +var i: LongInt; +begin + i:= PHYSFS_init(Str2PChar(ParamStr(0))); + AddFileLog('[PhysFS] init: ' + inttostr(i)); + + i:= PHYSFS_mount(Str2PChar(PathPrefix), nil, true); + AddFileLog('[PhysFS] mount ' + PathPrefix + ': ' + inttostr(i)); + i:= PHYSFS_mount(Str2PChar(UserPathPrefix + '/Data'), nil, true); + AddFileLog('[PhysFS] mount ' + UserPathPrefix + '/Data: ' + inttostr(i)); + + hedgewarsMountPackages; +end; + +procedure freeModule; +begin + PHYSFS_deinit; +end; + +end. diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uScript.pas --- a/hedgewars/uScript.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uScript.pas Sat Nov 17 20:30:32 2012 -0500 @@ -81,7 +81,9 @@ uLandGraphics, SDLh, SysUtils, - uIO; + uIO, + uPhysFSLayer + ; var luaState : Plua_State; ScriptAmmoLoadout : shortstring; @@ -1592,7 +1594,7 @@ lua_pushnil(L); end else - lua_pushstring(L, str2pchar(Pathz[ptData])); + lua_pushstring(L, str2pchar(cPathz[ptData])); lc_getdatapath:= 1 end; @@ -1604,7 +1606,7 @@ lua_pushnil(L); end else - lua_pushstring(L, str2pchar(UserPathz[ptData])); + lua_pushstring(L, str2pchar(cPathz[ptData])); lc_getuserdatapath:= 1 end; @@ -1792,6 +1794,18 @@ lc_setaihintsongear:= 0 end; + +function lc_hedgewarsscriptload(L : Plua_State) : LongInt; Cdecl; +begin + if lua_gettop(L) <> 1 then + begin + LuaError('Lua: Wrong number of parameters passed to HedgewarsScriptLoad!'); + lua_pushnil(L) + end + else + ScriptLoad(lua_tostring(L, 1)); + lc_hedgewarsscriptload:= 0; +end; /////////////////// procedure ScriptPrintStack; @@ -1964,18 +1978,30 @@ ScriptCall('onScreenResize'); end; +// custom script loader via physfs, passed to lua_load +const BUFSIZE = 1024; +var physfsReaderBuffer: pointer; external; +function physfsReader(L: Plua_State; f: PFSFile; sz: Psize_t) : PChar; cdecl; external; + procedure ScriptLoad(name : shortstring); var ret : LongInt; s : shortstring; + f : PFSFile; + buf : array[0..Pred(BUFSIZE)] of byte; begin -s:= UserPathz[ptData] + '/' + name; -if not FileExists(s) then - s:= Pathz[ptData] + '/' + name; -if not FileExists(s) then +s:= cPathz[ptData] + name; +if not pfsExists(s) then exit; -ret:= luaL_loadfile(luaState, Str2PChar(s)); +f:= pfsOpenRead(s); +if f = nil then + exit; + +physfsReaderBuffer:= @buf; +ret:= lua_load(luaState, @physfsReader, f, Str2PChar(s)); +pfsClose(f); + if ret <> 0 then begin LuaError('Lua: Failed to load ' + name + '(error ' + IntToStr(ret) + ')'); @@ -2393,6 +2419,7 @@ lua_register(luaState, _P'TestRectForObstacle', @lc_testrectforobstacle); lua_register(luaState, _P'SetGearAIHints', @lc_setaihintsongear); +lua_register(luaState, _P'HedgewarsScriptLoad', @lc_hedgewarsscriptload); ScriptClearStack; // just to be sure stack is empty diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uSound.pas --- a/hedgewars/uSound.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uSound.pas Sat Nov 17 20:30:32 2012 -0500 @@ -106,7 +106,7 @@ implementation -uses uVariables, uConsole, uUtils, uCommands, uDebug; +uses uVariables, uConsole, uUtils, uCommands, uDebug, uPhysFSLayer; const chanTPU = 32; var Volume: LongInt; @@ -131,29 +131,17 @@ if cLocale <> 'en' then begin locName:= name+'_'+cLocale; - path:= UserPathz[ptVoices] + '/' + locName; + path:= cPathz[ptVoices] + '/' + locName; if DirectoryExists(path) then name:= locName else - begin - path:= Pathz[ptVoices] + '/' + locName; - if DirectoryExists(path) then - name:= locName - else if Length(cLocale) > 3 - then + if Length(cLocale) > 3 then begin locName:= name+'_'+Copy(cLocale,1,2); - path:= UserPathz[ptVoices] + '/' + locName; + path:= cPathz[ptVoices] + '/' + locName; if DirectoryExists(path) then name:= locName - else - begin - path:= Pathz[ptVoices] + '/' + locName; - if DirectoryExists(path) then - name:= locName - end end - end end; // If that fails, use the unmodified one @@ -267,13 +255,11 @@ begin if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then begin - s:= UserPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; - if not FileExists(s) then - s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; + s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; if (not FileExists(s)) and (snd in [sndFirePunch2, sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6]) then - s:= Pathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; + s:= cPathz[Soundz[sndFirePunch1].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; WriteToConsole(msgLoading + s + ' '); - voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1); + voicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1); if voicepack^.chunks[snd] = nil then WriteLnToConsole(msgFailed) else @@ -285,11 +271,9 @@ begin if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then begin - s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; - if not FileExists(s) then - s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; + s:= cPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; WriteToConsole(msgLoading + s + ' '); - defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1); + defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1); SDLTry(defVoicepack^.chunks[snd] <> nil, true); WriteLnToConsole(msgOK); end; @@ -369,11 +353,9 @@ begin if (voicepack^.chunks[snd] = nil) and (Soundz[snd].Path = ptVoices) and (Soundz[snd].FileName <> '') then begin - s:= UserPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; - if not FileExists(s) then - s:= Pathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; + s:= cPathz[Soundz[snd].Path] + '/' + voicepack^.name + '/' + Soundz[snd].FileName; WriteToConsole(msgLoading + s + ' '); - voicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1); + voicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1); if voicepack^.chunks[snd] = nil then WriteLnToConsole(msgFailed) else @@ -385,11 +367,9 @@ begin if (defVoicepack^.chunks[snd] = nil) and (Soundz[snd].Path <> ptVoices) and (Soundz[snd].FileName <> '') then begin - s:= UserPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; - if not FileExists(s) then - s:= Pathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; + s:= cPathz[Soundz[snd].Path] + '/' + Soundz[snd].FileName; WriteToConsole(msgLoading + s + ' '); - defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), _P'rb'), 1); + defVoicepack^.chunks[snd]:= Mix_LoadWAV_RW(rwopsOpenRead(s), 1); SDLTry(defVoicepack^.chunks[snd] <> nil, true); WriteLnToConsole(msgOK); end; @@ -436,12 +416,10 @@ if (not isSoundEnabled) or (MusicFN = '') or (not isMusicEnabled) then exit; - s:= UserPathPrefix + '/Data/Music/' + MusicFN; - if not FileExists(s) then - s:= PathPrefix + '/Music/' + MusicFN; + s:= '/Music/' + MusicFN; WriteToConsole(msgLoading + s + ' '); - Mus:= Mix_LoadMUS(Str2PChar(s)); + Mus:= Mix_LoadMUS_RW(rwopsOpenRead(s)); SDLTry(Mus <> nil, false); WriteLnToConsole(msgOK); diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uStore.pas Sat Nov 17 20:30:32 2012 -0500 @@ -56,9 +56,11 @@ procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF}; implementation -uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands, - uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF} - {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF}; +uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands + , uPhysFSLayer + , uDebug + {$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF} + {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF}; //type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple); @@ -309,11 +311,9 @@ for fi:= Low(THWFont) to High(THWFont) do with Fontz[fi] do begin - s:= UserPathz[ptFonts] + '/' + Name; - if not FileExists(s) then - s:= Pathz[ptFonts] + '/' + Name; + s:= cPathz[ptFonts] + '/' + Name; WriteToConsole(msgLoading + s + ' (' + inttostr(Height) + 'pt)... '); - Handle:= TTF_OpenFont(Str2PChar(s), Height); + Handle:= TTF_OpenFontRW(rwopsOpenRead(s), true, Height); SDLTry(Handle <> nil, true); TTF_SetFontStyle(Handle, style); WriteLnToConsole(msgOK) @@ -565,7 +565,7 @@ WriteToConsole(msgLoading + filename + '.png [flags: ' + inttostr(imageFlags) + '] '); s:= filename + '.png'; - tmpsurf:= IMG_Load(Str2PChar(s)); + tmpsurf:= IMG_Load_RW(rwopsOpenRead(s), true); if tmpsurf = nil then begin @@ -597,13 +597,7 @@ var tmpsurf: PSDL_Surface; begin // check for file in user dir (never critical) - tmpsurf:= LoadImage(UserPathz[path] + '/' + filename, imageFlags and (not ifCritical)); - - // if unsuccessful check data dir - if (tmpsurf = nil) then - tmpsurf:= LoadImage(Pathz[path] + '/' + filename, imageFlags); - - LoadDataImage:= tmpsurf; + tmpsurf:= LoadImage(cPathz[path] + '/' + filename, imageFlags); end; diff -r 39f8ea1a441f -r bcebfc477459 hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Sat Nov 17 20:27:49 2012 -0500 +++ b/hedgewars/uVariables.pas Sat Nov 17 20:30:32 2012 -0500 @@ -118,9 +118,6 @@ SDWaterOpacity: byte; GrayScale: Boolean; - // originally from uConsts - Pathz: array[TPathType] of shortstring; - UserPathz: array[TPathType] of shortstring; CountTexz: array[0..Pred(AMMO_INFINITE)] of PTexture; LAND_WIDTH : LongInt; LAND_HEIGHT : LongInt; @@ -225,27 +222,27 @@ // these consts are here because they would cause circular dependencies in uConsts/uTypes cPathz: array[TPathType] of shortstring = ( '', // ptNone - '', // ptData - 'Graphics', // ptGraphics - 'Themes', // ptThemes - 'Themes/Bamboo', // ptCurrTheme - 'Teams', // ptTeams - 'Maps', // ptMaps + '/', // ptData + '/Graphics', // ptGraphics + '/Themes', // ptThemes + '/Themes/Bamboo', // ptCurrTheme + '/Teams', // ptTeams + '/Maps', // ptMaps '', // ptMapCurrent - 'Demos', // ptDemos - 'Sounds', // ptSounds - 'Graphics/Graves', // ptGraves - 'Fonts', // ptFonts - 'Forts', // ptForts - 'Locale', // ptLocale - 'Graphics/AmmoMenu', // ptAmmoMenu - 'Graphics/Hedgehog', // ptHedgehog - 'Sounds/voices', // ptVoices - 'Graphics/Hats', // ptHats - 'Graphics/Flags', // ptFlags - 'Missions/Maps', // ptMissionMaps - 'Graphics/SuddenDeath', // ptSuddenDeath - 'Graphics/Buttons' // ptButton + '/Demos', // ptDemos + '/Sounds', // ptSounds + '/Graphics/Graves', // ptGraves + '/Fonts', // ptFonts + '/Forts', // ptForts + '/Locale', // ptLocale + '/Graphics/AmmoMenu', // ptAmmoMenu + '/Graphics/Hedgehog', // ptHedgehog + '/Sounds/voices', // ptVoices + '/Graphics/Hats', // ptHats + '/Graphics/Flags', // ptFlags + '/Missions/Maps', // ptMissionMaps + '/Graphics/SuddenDeath', // ptSuddenDeath + '/Graphics/Buttons' // ptButton ); Fontz: array[THWFont] of THHFont = ( @@ -2586,7 +2583,6 @@ lastVisualGearByUID := nil; lastGearByUID := nil; cReadyDelay := 5000; - Pathz := cPathz; {* REFERENCE 4096 -> $FFFFF000 diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/CMakeLists.txt Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,546 @@ +# PhysicsFS; a portable, flexible file i/o abstraction. +# Copyright (C) 2007 Ryan C. Gordon. +# +# Please see the file LICENSE.txt in the source's root directory. + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4) + +PROJECT(PhysicsFS) +SET(PHYSFS_VERSION 2.1.0) + +# Increment this if/when we break backwards compatibility. +SET(PHYSFS_SOVERSION 1) + +# I hate that they define "WIN32" ... we're about to move to Win64...I hope! +IF(WIN32 AND NOT WINDOWS) + SET(WINDOWS TRUE) +ENDIF(WIN32 AND NOT WINDOWS) + +# Bleh, let's do it for "APPLE" too. +IF(APPLE AND NOT MACOSX) + SET(MACOSX TRUE) +ENDIF(APPLE AND NOT MACOSX) + +# For now, Haiku and BeOS are the same, as far as the build system cares. +IF(HAIKU AND NOT BEOS) + SET(BEOS TRUE) +ENDIF(HAIKU AND NOT BEOS) + +IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + SET(SOLARIS TRUE) +ENDIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") + +INCLUDE(CheckIncludeFile) +INCLUDE(CheckLibraryExists) +INCLUDE(CheckCSourceCompiles) + +INCLUDE_DIRECTORIES(./src) + +IF(MACOSX) + # Fallback to older OS X on PowerPC to support wider range of systems... + IF(CMAKE_OSX_ARCHITECTURES MATCHES ppc) + ADD_DEFINITIONS(-DMAC_OS_X_VERSION_MIN_REQUIRED=1020) + SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} " -mmacosx-version-min=10.2") + ENDIF(CMAKE_OSX_ARCHITECTURES MATCHES ppc) + + # Need these everywhere... + ADD_DEFINITIONS(-fno-common) + SET(OTHER_LDFLAGS ${OTHER_LDFLAGS} "-framework Carbon -framework IOKit") +ENDIF(MACOSX) + +# Add some gcc-specific command lines. +IF(CMAKE_COMPILER_IS_GNUCC) + # Always build with debug symbols...you can strip it later. + ADD_DEFINITIONS(-g -pipe -Werror -fsigned-char) + + # Stupid BeOS generates warnings in the system headers. + IF(NOT BEOS) + ADD_DEFINITIONS(-Wall) + ENDIF(NOT BEOS) + + CHECK_C_SOURCE_COMPILES(" + #if ((defined(__GNUC__)) && (__GNUC__ >= 4)) + int main(int argc, char **argv) { int is_gcc4 = 1; return 0; } + #else + #error This is not gcc4. + #endif + " PHYSFS_IS_GCC4) + + IF(PHYSFS_IS_GCC4) + # Not supported on several operating systems at this time. + IF(NOT SOLARIS AND NOT WINDOWS) + ADD_DEFINITIONS(-fvisibility=hidden) + ENDIF(NOT SOLARIS AND NOT WINDOWS) + ENDIF(PHYSFS_IS_GCC4) + + # Don't use -rpath. + SET(CMAKE_SKIP_RPATH ON CACHE BOOL "Skip RPATH" FORCE) +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +IF(CMAKE_C_COMPILER_ID STREQUAL "SunPro") + ADD_DEFINITIONS(-erroff=E_EMPTY_TRANSLATION_UNIT) + ADD_DEFINITIONS(-xldscope=hidden) +ENDIF(CMAKE_C_COMPILER_ID STREQUAL "SunPro") + +IF(MSVC) + # VS.NET 8.0 got really really anal about strcpy, etc, which even if we + # cleaned up our code, zlib, etc still use...so disable the warning. + ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS=1) +ENDIF(MSVC) + +# Basic chunks of source code ... + +SET(LZMA_SRCS + src/lzma/C/7zCrc.c + src/lzma/C/Archive/7z/7zBuffer.c + src/lzma/C/Archive/7z/7zDecode.c + src/lzma/C/Archive/7z/7zExtract.c + src/lzma/C/Archive/7z/7zHeader.c + src/lzma/C/Archive/7z/7zIn.c + src/lzma/C/Archive/7z/7zItem.c + src/lzma/C/Archive/7z/7zMethodID.c + src/lzma/C/Compress/Branch/BranchX86.c + src/lzma/C/Compress/Branch/BranchX86_2.c + src/lzma/C/Compress/Lzma/LzmaDecode.c +) + +IF(BEOS) + # We add this explicitly, since we don't want CMake to think this + # is a C++ project unless we're on BeOS. + SET(PHYSFS_BEOS_SRCS src/platform_beos.cpp) + FIND_LIBRARY(BE_LIBRARY be) + FIND_LIBRARY(ROOT_LIBRARY root) + SET(OPTIONAL_LIBRARY_LIBS ${OPTIONAL_LIBRARY_LIBS} ${BE_LIBRARY} ${ROOT_LIBRARY}) +ENDIF(BEOS) + +# Almost everything is "compiled" here, but things that don't apply to the +# build are #ifdef'd out. This is to make it easy to embed PhysicsFS into +# another project or bring up a new build system: just compile all the source +# code and #define the things you want. +SET(PHYSFS_SRCS + src/physfs.c + src/physfs_byteorder.c + src/physfs_unicode.c + src/platform_posix.c + src/platform_unix.c + src/platform_macosx.c + src/platform_windows.c + src/archiver_dir.c + src/archiver_unpacked.c + src/archiver_grp.c + src/archiver_hog.c + src/archiver_lzma.c + src/archiver_mvl.c + src/archiver_qpak.c + src/archiver_wad.c + src/archiver_zip.c + src/archiver_iso9660.c + ${PHYSFS_BEOS_SRCS} +) + + +# platform layers ... + +IF(UNIX) + IF(BEOS) + SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE) + SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE) + SET(HAVE_PTHREAD_H TRUE) + ELSE(BEOS) + CHECK_INCLUDE_FILE(sys/ucred.h HAVE_UCRED_H) + IF(HAVE_UCRED_H) + ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_UCRED_H=1) + SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE) + ENDIF(HAVE_UCRED_H) + + CHECK_INCLUDE_FILE(mntent.h HAVE_MNTENT_H) + IF(HAVE_MNTENT_H) + ADD_DEFINITIONS(-DPHYSFS_HAVE_MNTENT_H=1) + SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE) + ENDIF(HAVE_MNTENT_H) + + # !!! FIXME: Solaris fails this, because mnttab.h implicitly + # !!! FIXME: depends on other system headers. :( + #CHECK_INCLUDE_FILE(sys/mnttab.h HAVE_SYS_MNTTAB_H) + CHECK_C_SOURCE_COMPILES(" + #include + #include + int main(int argc, char **argv) { return 0; } + " HAVE_SYS_MNTTAB_H) + + IF(HAVE_SYS_MNTTAB_H) + ADD_DEFINITIONS(-DPHYSFS_HAVE_SYS_MNTTAB_H=1) + SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE) + ENDIF(HAVE_SYS_MNTTAB_H) + + CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H) + IF(HAVE_PTHREAD_H) + SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE) + ENDIF(HAVE_PTHREAD_H) + ENDIF(BEOS) +ENDIF(UNIX) + +IF(WINDOWS) + SET(PHYSFS_HAVE_CDROM_SUPPORT TRUE) + SET(PHYSFS_HAVE_THREAD_SUPPORT TRUE) +ENDIF(WINDOWS) + +IF(NOT PHYSFS_HAVE_CDROM_SUPPORT) + ADD_DEFINITIONS(-DPHYSFS_NO_CDROM_SUPPORT=1) + MESSAGE(WARNING " ***") + MESSAGE(WARNING " *** There is no CD-ROM support in this build!") + MESSAGE(WARNING " *** PhysicsFS will just pretend there are no discs.") + MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,") + MESSAGE(WARNING " *** but is this what you REALLY wanted?") + MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)") + MESSAGE(WARNING " ***") +ENDIF(NOT PHYSFS_HAVE_CDROM_SUPPORT) + +IF(PHYSFS_HAVE_THREAD_SUPPORT) + ADD_DEFINITIONS(-D_REENTRANT -D_THREAD_SAFE) +ELSE(PHYSFS_HAVE_THREAD_SUPPORT) + ADD_DEFINITIONS(-DPHYSFS_NO_THREAD_SUPPORT=1) + MESSAGE(WARNING " ***") + MESSAGE(WARNING " *** There is no thread support in this build!") + MESSAGE(WARNING " *** PhysicsFS will NOT be reentrant!") + MESSAGE(WARNING " *** This may be fine, depending on how PhysicsFS is used,") + MESSAGE(WARNING " *** but is this what you REALLY wanted?") + MESSAGE(WARNING " *** (Maybe fix CMakeLists.txt, or write a platform driver?)") + MESSAGE(WARNING " ***") +ENDIF(PHYSFS_HAVE_THREAD_SUPPORT) + + +# Archivers ... + +OPTION(PHYSFS_ARCHIVE_ZIP "Enable ZIP support" TRUE) +IF(PHYSFS_ARCHIVE_ZIP) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ZIP=1) +ENDIF(PHYSFS_ARCHIVE_ZIP) + +OPTION(PHYSFS_ARCHIVE_7Z "Enable 7zip support" FALSE) +IF(PHYSFS_ARCHIVE_7Z) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_7Z=1) + # !!! FIXME: rename to 7z.c? + SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${LZMA_SRCS}) +ENDIF(PHYSFS_ARCHIVE_7Z) + +OPTION(PHYSFS_ARCHIVE_GRP "Enable Build Engine GRP support" TRUE) +IF(PHYSFS_ARCHIVE_GRP) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_GRP=1) +ENDIF(PHYSFS_ARCHIVE_GRP) + +OPTION(PHYSFS_ARCHIVE_WAD "Enable Doom WAD support" TRUE) +IF(PHYSFS_ARCHIVE_WAD) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_WAD=1) +ENDIF(PHYSFS_ARCHIVE_WAD) + +OPTION(PHYSFS_ARCHIVE_HOG "Enable Descent I/II HOG support" TRUE) +IF(PHYSFS_ARCHIVE_HOG) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_HOG=1) +ENDIF(PHYSFS_ARCHIVE_HOG) + +OPTION(PHYSFS_ARCHIVE_MVL "Enable Descent I/II MVL support" TRUE) +IF(PHYSFS_ARCHIVE_MVL) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_MVL=1) +ENDIF(PHYSFS_ARCHIVE_MVL) + +OPTION(PHYSFS_ARCHIVE_QPAK "Enable Quake I/II QPAK support" TRUE) +IF(PHYSFS_ARCHIVE_QPAK) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_QPAK=1) +ENDIF(PHYSFS_ARCHIVE_QPAK) + +OPTION(PHYSFS_ARCHIVE_ISO9660 "Enable ISO9660 support" TRUE) +IF(PHYSFS_ARCHIVE_ISO9660) + ADD_DEFINITIONS(-DPHYSFS_SUPPORTS_ISO9660=1) +ENDIF(PHYSFS_ARCHIVE_ISO9660) + + +OPTION(PHYSFS_BUILD_STATIC "Build static library" TRUE) +IF(PHYSFS_BUILD_STATIC) + ADD_LIBRARY(physfs STATIC ${PHYSFS_SRCS}) + SET_TARGET_PROPERTIES(physfs PROPERTIES OUTPUT_NAME "physfs") + SET(PHYSFS_LIB_TARGET physfs) + SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs") +ENDIF(PHYSFS_BUILD_STATIC) + +#OPTION(PHYSFS_BUILD_SHARED "Build shared library" FALSE) +#IF(PHYSFS_BUILD_SHARED) +# ADD_LIBRARY(physfs SHARED ${PHYSFS_SRCS}) +# SET_TARGET_PROPERTIES(physfs PROPERTIES VERSION ${PHYSFS_VERSION}) +# SET_TARGET_PROPERTIES(physfs PROPERTIES SOVERSION ${PHYSFS_SOVERSION}) +# TARGET_LINK_LIBRARIES(physfs ${OPTIONAL_LIBRARY_LIBS} ${OTHER_LDFLAGS}) +# SET(PHYSFS_LIB_TARGET physfs) +# SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";physfs") +#ENDIF(PHYSFS_BUILD_SHARED) + +IF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC) + MESSAGE(FATAL "Both shared and static libraries are disabled!") +ENDIF(NOT PHYSFS_BUILD_SHARED AND NOT PHYSFS_BUILD_STATIC) + +# CMake FAQ says I need this... +IF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC) + SET_TARGET_PROPERTIES(physfs PROPERTIES CLEAN_DIRECT_OUTPUT 1) + SET_TARGET_PROPERTIES(physfs-static PROPERTIES CLEAN_DIRECT_OUTPUT 1) +ENDIF(PHYSFS_BUILD_SHARED AND PHYSFS_BUILD_STATIC) + +OPTION(PHYSFS_BUILD_TEST "Build stdio test program." FALSE) +MARK_AS_ADVANCED(PHYSFS_BUILD_TEST) +IF(PHYSFS_BUILD_TEST) + FIND_PATH(READLINE_H readline/readline.h) + FIND_PATH(HISTORY_H readline/history.h) + IF(READLINE_H AND HISTORY_H) + FIND_LIBRARY(CURSES_LIBRARY NAMES curses ncurses) + SET(CMAKE_REQUIRED_LIBRARIES ${CURSES_LIBRARY}) + FIND_LIBRARY(READLINE_LIBRARY readline) + IF(READLINE_LIBRARY) + SET(HAVE_SYSTEM_READLINE TRUE) + SET(TEST_PHYSFS_LIBS ${TEST_PHYSFS_LIBS} ${READLINE_LIBRARY} ${CURSES_LIBRARY}) + INCLUDE_DIRECTORIES(${READLINE_H} ${HISTORY_H}) + ADD_DEFINITIONS(-DPHYSFS_HAVE_READLINE=1) + ENDIF(READLINE_LIBRARY) + ENDIF(READLINE_H AND HISTORY_H) + ADD_EXECUTABLE(test_physfs test/test_physfs.c) + TARGET_LINK_LIBRARIES(test_physfs ${PHYSFS_LIB_TARGET} ${TEST_PHYSFS_LIBS} ${OTHER_LDFLAGS}) + SET(PHYSFS_INSTALL_TARGETS ${PHYSFS_INSTALL_TARGETS} ";test_physfs") +ENDIF(PHYSFS_BUILD_TEST) + + +# Scripting language bindings... + +#CMake's SWIG support is basically useless. +#FIND_PACKAGE(SWIG) + +OPTION(PHYSFS_BUILD_SWIG "Build ${_LANG} bindings." FALSE) +MARK_AS_ADVANCED(PHYSFS_BUILD_SWIG) + +FIND_PROGRAM(SWIG swig DOC "Path to swig command line app: http://swig.org/") +IF(NOT SWIG) + MESSAGE(STATUS "SWIG not found. You won't be able to build scripting language bindings.") +ELSE(NOT SWIG) + MARK_AS_ADVANCED(SWIG) + IF(DEFINED CMAKE_BUILD_TYPE) + IF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")) + IF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + SET(SWIG_OPT_CFLAGS "-small") + ELSE(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + SET(SWIG_OPT_CFLAGS "-O") + ENDIF(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + ENDIF((NOT CMAKE_BUILD_TYPE STREQUAL "") AND (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")) + ENDIF(DEFINED CMAKE_BUILD_TYPE) + + SET(SWIG_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/physfs-swig-bindings") + + MACRO(CONFIGURE_SWIG_BINDING _LANG _INSTALLPATH _EXTRAOUTPUTS _EXTRACFLAGS _EXTRALDFLAGS) + STRING(TOUPPER "${_LANG}" _UPPERLANG) + STRING(TOLOWER "${_LANG}" _LOWERLANG) + SET(_TARGET "physfs-${_LOWERLANG}") + SET(_TARGETDIR "${SWIG_OUTPUT_DIR}/${_LOWERLANG}") + + IF(NOT EXISTS "${_TARGETDIR}") + FILE(MAKE_DIRECTORY "${_TARGETDIR}") + ENDIF(NOT EXISTS "${_TARGETDIR}") + + IF(PHYSFS_BUILD_${_UPPERLANG}) + ADD_CUSTOM_COMMAND( + OUTPUT "${_TARGETDIR}/${_TARGET}.c" ${_EXTRAOUTPUTS} + MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i" + COMMAND "${SWIG}" + ARGS ${SWIG_OPT_CFLAGS} -${_LOWERLANG} -outdir "${_TARGETDIR}" -o "${_TARGETDIR}/${_TARGET}.c" "${CMAKE_CURRENT_SOURCE_DIR}/extras/physfs-swig.i" + COMMENT "Generating ${_LANG} bindings..." + ) + + ADD_LIBRARY(${_TARGET} SHARED "${_TARGETDIR}/${_TARGET}.c") + TARGET_LINK_LIBRARIES(${_TARGET} ${PHYSFS_LIB_TARGET}) + SET_TARGET_PROPERTIES(${_TARGET} PROPERTIES + COMPILE_FLAGS "${_EXTRACFLAGS}" + LINK_FLAGS "${_EXTRALDFLAGS}" + LIBRARY_OUTPUT_NAME "physfs" + LIBRARY_OUTPUT_DIRECTORY "${_TARGETDIR}" + CLEAN_DIRECT_OUTPUT 1 + ) + INSTALL(TARGETS ${_TARGET} LIBRARY DESTINATION "${_INSTALLPATH}") + MESSAGE(STATUS "${_LANG} bindings configured!") + ELSE(PHYSFS_BUILD_${_UPPERLANG}) + MESSAGE(STATUS "Couldn't figure out ${_LANG} configuration. Skipping ${_LANG} bindings.") + ENDIF(PHYSFS_BUILD_${_UPPERLANG}) + ENDMACRO(CONFIGURE_SWIG_BINDING) + + MACRO(ADD_SCRIPT_BINDING_OPTION _VAR _LANG _DEFVAL) + SET(BUILDSWIGVAL ${_DEFVAL}) + IF(NOT PHYSFS_BUILD_SWIG) + SET(BUILDSWIGVAL FALSE) + ENDIF(NOT PHYSFS_BUILD_SWIG) + OPTION(${_VAR} "Build ${_LANG} bindings." ${BUILDSWIGVAL}) + MARK_AS_ADVANCED(${_VAR}) + ENDMACRO(ADD_SCRIPT_BINDING_OPTION) + + ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_PERL "Perl" TRUE) + ADD_SCRIPT_BINDING_OPTION(PHYSFS_BUILD_RUBY "Ruby" TRUE) +ENDIF(NOT SWIG) + +IF(PHYSFS_BUILD_PERL) + MESSAGE(STATUS "Configuring Perl bindings...") + FIND_PROGRAM(PERL perl DOC "Path to perl command line app: http://perl.org/") + IF(NOT PERL) + MESSAGE(STATUS "Perl not found. You won't be able to build perl bindings.") + SET(PHYSFS_BUILD_PERL FALSE) + ENDIF(NOT PERL) + MARK_AS_ADVANCED(PERL) + + MACRO(GET_PERL_CONFIG _KEY _VALUE) + IF(PHYSFS_BUILD_PERL) + MESSAGE(STATUS "Figuring out perl config value '${_KEY}' ...") + EXECUTE_PROCESS( + COMMAND ${PERL} -w -e "use Config; print \$Config{${_KEY}};" + RESULT_VARIABLE GET_PERL_CONFIG_RC + OUTPUT_VARIABLE ${_VALUE} + ) + IF(NOT GET_PERL_CONFIG_RC EQUAL 0) + MESSAGE(STATUS "Perl executable ('${PERL}') reported failure: ${GET_PERL_CONFIG_RC}") + SET(PHYSFS_BUILD_PERL FALSE) + ENDIF(NOT GET_PERL_CONFIG_RC EQUAL 0) + IF(NOT ${_VALUE}) + MESSAGE(STATUS "Perl executable ('${PERL}') didn't have a value for '${_KEY}'") + SET(PHYSFS_BUILD_PERL FALSE) + ENDIF(NOT ${_VALUE}) + + IF(PHYSFS_BUILD_PERL) + MESSAGE(STATUS "Perl says: '${${_VALUE}}'.") + ENDIF(PHYSFS_BUILD_PERL) + ENDIF(PHYSFS_BUILD_PERL) + ENDMACRO(GET_PERL_CONFIG) + + # !!! FIXME: installsitearch might be the wrong location. + GET_PERL_CONFIG("archlibexp" PERL_INCLUDE_PATH) + GET_PERL_CONFIG("ccflags" PERL_CCFLAGS) + GET_PERL_CONFIG("ldflags" PERL_LDFLAGS) + GET_PERL_CONFIG("installsitearch" PERL_INSTALL_PATH) + + # !!! FIXME: this test for Mac OS X is wrong. + IF(MACOSX) + GET_PERL_CONFIG("libperl" PERL_LIBPERL) + SET(TMPLIBPERL "${PERL_LIBPERL}") + STRING(REGEX REPLACE "^lib" "" TMPLIBPERL "${TMPLIBPERL}") + STRING(REGEX REPLACE "\\.so$" "" TMPLIBPERL "${TMPLIBPERL}") + STRING(REGEX REPLACE "\\.dylib$" "" TMPLIBPERL "${TMPLIBPERL}") + STRING(REGEX REPLACE "\\.dll$" "" TMPLIBPERL "${TMPLIBPERL}") + IF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}") + MESSAGE(STATUS "Stripped '${PERL_LIBPERL}' down to '${TMPLIBPERL}'.") + SET(PERL_LIBPERL "${TMPLIBPERL}") + ENDIF(NOT "${TMPLIBPERL}" STREQUAL "${PERL_LIBPERL}") + SET(PERL_LIBPERL "-l${PERL_LIBPERL}") + ENDIF(MACOSX) + + CONFIGURE_SWIG_BINDING(Perl "${PERL_INSTALL_PATH}" "${SWIG_OUTPUT_DIR}/perl/physfs.pm" "\"-I${PERL_INCLUDE_PATH}/CORE\" ${PERL_CCFLAGS} -w" "\"-L${PERL_INCLUDE_PATH}/CORE\" ${PERL_LIBPERL} ${PERL_LDFLAGS}") + INSTALL(FILES "${SWIG_OUTPUT_DIR}/perl/physfs.pm" DESTINATION "${PERL_INSTALL_PATH}") + INSTALL( + FILES test/test_physfs.pl + DESTINATION bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + ) +ENDIF(PHYSFS_BUILD_PERL) + +# !!! FIXME: lots of cut-and-paste from perl bindings. +IF(PHYSFS_BUILD_RUBY) + MESSAGE(STATUS "Configuring Ruby bindings...") + FIND_PROGRAM(RUBY ruby DOC "Path to ruby command line app: http://ruby-lang.org/") + IF(NOT RUBY) + MESSAGE(STATUS "Ruby not found. You won't be able to build ruby bindings.") + SET(PHYSFS_BUILD_RUBY FALSE) + ENDIF(NOT RUBY) + MARK_AS_ADVANCED(RUBY) + + MACRO(GET_RUBY_CONFIG _KEY _VALUE) + IF(PHYSFS_BUILD_RUBY) + MESSAGE(STATUS "Figuring out ruby config value '${_KEY}' ...") + EXECUTE_PROCESS( + COMMAND ${RUBY} -e "require 'rbconfig'; puts RbConfig::CONFIG['${_KEY}'];" + RESULT_VARIABLE GET_RUBY_CONFIG_RC + OUTPUT_VARIABLE ${_VALUE} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + IF(NOT GET_RUBY_CONFIG_RC EQUAL 0) + MESSAGE(STATUS "Ruby executable ('${RUBY}') reported failure: ${GET_RUBY_CONFIG_RC}") + SET(PHYSFS_BUILD_RUBY FALSE) + ENDIF(NOT GET_RUBY_CONFIG_RC EQUAL 0) + IF(NOT ${_VALUE}) + MESSAGE(STATUS "Ruby executable ('${RUBY}') didn't have a value for '${_KEY}'") + SET(PHYSFS_BUILD_RUBY FALSE) + ENDIF(NOT ${_VALUE}) + + IF(PHYSFS_BUILD_RUBY) + MESSAGE(STATUS "Ruby says: '${${_VALUE}}'.") + ENDIF(PHYSFS_BUILD_RUBY) + ENDIF(PHYSFS_BUILD_RUBY) + ENDMACRO(GET_RUBY_CONFIG) + + GET_RUBY_CONFIG("archdir" RUBY_INCLUDE_PATH) + GET_RUBY_CONFIG("CFLAGS" RUBY_CCFLAGS) + GET_RUBY_CONFIG("LDFLAGS" RUBY_LDFLAGS) + GET_RUBY_CONFIG("sitearchdir" RUBY_INSTALL_PATH) + GET_RUBY_CONFIG("LIBRUBYARG_SHARED" RUBY_LIBRUBY) + GET_RUBY_CONFIG("libdir" RUBY_LIBDIR) + + CONFIGURE_SWIG_BINDING(Ruby "${RUBY_INSTALL_PATH}" "" "\"-I${RUBY_INCLUDE_PATH}\" ${RUBY_CCFLAGS} -w" "\"-L${RUBY_LIBDIR}\" ${RUBY_LIBRUBY} ${RUBY_LDFLAGS}") + SET_TARGET_PROPERTIES(physfs-ruby PROPERTIES PREFIX "") + INSTALL( + FILES test/test_physfs.rb + DESTINATION bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + ) +ENDIF(PHYSFS_BUILD_RUBY) + + +INSTALL(TARGETS ${PHYSFS_INSTALL_TARGETS} + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) +INSTALL(FILES src/physfs.h DESTINATION include) + +IF(UNIX) + SET(PHYSFS_TARBALL "${CMAKE_CURRENT_SOURCE_DIR}/../physfs-${PHYSFS_VERSION}.tar.gz") + ADD_CUSTOM_TARGET( + dist + hg archive -t tgz "${PHYSFS_TARBALL}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Building source tarball '${PHYSFS_TARBALL}'..." + ) +# ADD_CUSTOM_TARGET( +# uninstall +# "${CMAKE_CURRENT_SOURCE_DIR}/extras/uninstall.sh" +# WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +# COMMENT "Uninstall the project..." +# ) +ENDIF(UNIX) + +MACRO(MESSAGE_BOOL_OPTION _NAME _VALUE) + IF(${_VALUE}) + MESSAGE(STATUS " ${_NAME}: enabled") + ELSE(${_VALUE}) + MESSAGE(STATUS " ${_NAME}: disabled") + ENDIF(${_VALUE}) +ENDMACRO(MESSAGE_BOOL_OPTION) + +MESSAGE(STATUS "PhysicsFS will build with the following options:") +MESSAGE_BOOL_OPTION("ZIP support" PHYSFS_ARCHIVE_ZIP) +MESSAGE_BOOL_OPTION("7zip support" PHYSFS_ARCHIVE_7Z) +MESSAGE_BOOL_OPTION("GRP support" PHYSFS_ARCHIVE_GRP) +MESSAGE_BOOL_OPTION("WAD support" PHYSFS_ARCHIVE_WAD) +MESSAGE_BOOL_OPTION("HOG support" PHYSFS_ARCHIVE_HOG) +MESSAGE_BOOL_OPTION("MVL support" PHYSFS_ARCHIVE_MVL) +MESSAGE_BOOL_OPTION("QPAK support" PHYSFS_ARCHIVE_QPAK) +MESSAGE_BOOL_OPTION("CD-ROM drive support" PHYSFS_HAVE_CDROM_SUPPORT) +MESSAGE_BOOL_OPTION("Thread safety" PHYSFS_HAVE_THREAD_SUPPORT) +MESSAGE_BOOL_OPTION("Build static library" PHYSFS_BUILD_STATIC) +MESSAGE_BOOL_OPTION("Build shared library" PHYSFS_BUILD_SHARED) +MESSAGE_BOOL_OPTION("Build Perl bindings" PHYSFS_BUILD_PERL) +MESSAGE_BOOL_OPTION("Build Ruby bindings" PHYSFS_BUILD_RUBY) +MESSAGE_BOOL_OPTION("Build stdio test program" PHYSFS_BUILD_TEST) +IF(PHYSFS_BUILD_TEST) + MESSAGE_BOOL_OPTION(" Use readline in test program" HAVE_SYSTEM_READLINE) +ENDIF(PHYSFS_BUILD_TEST) + +# end of CMakeLists.txt ... + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/CMakeLists.txt Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,9 @@ +find_package(SDL REQUIRED) + +include_directories(${SDL_INCLUDE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/misc/liblua) +include_directories(${CMAKE_SOURCE_DIR}/misc/physfs/src) + +add_library(physfsrwops STATIC physfsrwops.c physfslualoader.c hwpacksmounter.c) + +add_dependencies(physfsrwops lua) diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/hwpacksmounter.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/hwpacksmounter.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +#include "hwpacksmounter.h" + +void hedgewarsMountPackages() +{ + char ** filesList = PHYSFS_enumerateFiles("/"); + char **i; + + for (i = filesList; *i != NULL; i++) + { + char * fileName = *i; + int fileNameLength = strlen(fileName); + if (fileNameLength > 4) + if (strcmp(fileName + fileNameLength - 4, ".hwp") == 0) + { + const char * dir = PHYSFS_getRealDir(fileName); + if(dir) + { + char * fullPath = (char *)malloc(strlen(dir) + fileNameLength + 2); + strcpy(fullPath, dir); + strcat(fullPath, "/"); + strcat(fullPath, fileName); + + PHYSFS_mount(fullPath, NULL, 1); + + free(fullPath); + } + } + } + + PHYSFS_freeList(filesList); +} diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/hwpacksmounter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/hwpacksmounter.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,15 @@ +#ifndef HEDGEWARS_PACKAGES_MOUNTER_H +#define HEDGEWARS_PACKAGES_MOUNTER_H + +#ifdef __cplusplus +extern "C" { +#endif + +void hedgewarsMountPackages(); + + +#ifdef __cplusplus +} +#endif + +#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/physfslualoader.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/physfslualoader.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,24 @@ +#include +#include + +#define BUFSIZE 1024 + +void * physfsReaderBuffer; + +const char * physfsReader(lua_State *L, PHYSFS_File *f, size_t *size) +{ + + if(PHYSFS_eof(f)) + { + return NULL; + } + else + { + *size = PHYSFS_readBytes(f, physfsReaderBuffer, BUFSIZE); + + if(*size == 0) + return NULL; + else + return physfsReaderBuffer; + } +} diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/physfsrwops.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/physfsrwops.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,219 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL 1.2 falls under the LGPL license. SDL 1.3+ is zlib, like PhysicsFS. + * You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + */ + +#include /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */ +#include "physfsrwops.h" + +/* SDL's RWOPS interface changed a little in SDL 1.3... */ +#if defined(SDL_VERSION_ATLEAST) +#if SDL_VERSION_ATLEAST(1, 3, 0) +#define TARGET_SDL13 1 +#endif +#endif + +#if TARGET_SDL13 +static long SDLCALL physfsrwops_seek(struct SDL_RWops *rw, long offset, int whence) +#else +static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence) +#endif +{ + PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; + PHYSFS_sint64 pos = 0; + + if (whence == SEEK_SET) + pos = (PHYSFS_sint64) offset; + + else if (whence == SEEK_CUR) + { + const PHYSFS_sint64 current = PHYSFS_tell(handle); + if (current == -1) + { + SDL_SetError("Can't find position in file: %s", + PHYSFS_getLastError()); + return -1; + } /* if */ + + if (offset == 0) /* this is a "tell" call. We're done. */ + { + #if TARGET_SDL13 + return (long) current; + #else + return (int) current; + #endif + } /* if */ + + pos = current + ((PHYSFS_sint64) offset); + } /* else if */ + + else if (whence == SEEK_END) + { + const PHYSFS_sint64 len = PHYSFS_fileLength(handle); + if (len == -1) + { + SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError()); + return -1; + } /* if */ + + pos = len + ((PHYSFS_sint64) offset); + } /* else if */ + + else + { + SDL_SetError("Invalid 'whence' parameter."); + return -1; + } /* else */ + + if ( pos < 0 ) + { + SDL_SetError("Attempt to seek past start of file."); + return -1; + } /* if */ + + if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos)) + { + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + return -1; + } /* if */ + + #if TARGET_SDL13 + return (long) pos; + #else + return (int) pos; + #endif +} /* physfsrwops_seek */ + + +#if TARGET_SDL13 +static size_t SDLCALL physfsrwops_read(struct SDL_RWops *rw, void *ptr, + size_t size, size_t maxnum) +#else +static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum) +#endif +{ + PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; + const PHYSFS_uint64 readlen = (PHYSFS_uint64) (maxnum * size); + const PHYSFS_sint64 rc = PHYSFS_readBytes(handle, ptr, readlen); + if (rc != ((PHYSFS_sint64) readlen)) + { + if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */ + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + } /* if */ + + #if TARGET_SDL13 + return (size_t) rc; + #else + return (int) rc; + #endif +} /* physfsrwops_read */ + + +#if TARGET_SDL13 +static size_t SDLCALL physfsrwops_write(struct SDL_RWops *rw, const void *ptr, + size_t size, size_t num) +#else +static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num) +#endif +{ + PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; + const PHYSFS_uint64 writelen = (PHYSFS_uint64) (num * size); + const PHYSFS_sint64 rc = PHYSFS_writeBytes(handle, ptr, writelen); + if (rc != ((PHYSFS_sint64) writelen)) + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + + #if TARGET_SDL13 + return (size_t) rc; + #else + return (int) rc; + #endif +} /* physfsrwops_write */ + + +static int physfsrwops_close(SDL_RWops *rw) +{ + PHYSFS_File *handle = (PHYSFS_File *) rw->hidden.unknown.data1; + if (!PHYSFS_close(handle)) + { + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + return -1; + } /* if */ + + SDL_FreeRW(rw); + return 0; +} /* physfsrwops_close */ + + +static SDL_RWops *create_rwops(PHYSFS_File *handle) +{ + SDL_RWops *retval = NULL; + + if (handle == NULL) + SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError()); + else + { + retval = SDL_AllocRW(); + if (retval != NULL) + { + retval->seek = physfsrwops_seek; + retval->read = physfsrwops_read; + retval->write = physfsrwops_write; + retval->close = physfsrwops_close; + retval->hidden.unknown.data1 = handle; + } /* if */ + } /* else */ + + return retval; +} /* create_rwops */ + + +SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle) +{ + SDL_RWops *retval = NULL; + if (handle == NULL) + SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops()."); + else + retval = create_rwops(handle); + + return retval; +} /* PHYSFSRWOPS_makeRWops */ + + +SDL_RWops *PHYSFSRWOPS_openRead(const char *fname) +{ + return create_rwops(PHYSFS_openRead(fname)); +} /* PHYSFSRWOPS_openRead */ + + +SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname) +{ + return create_rwops(PHYSFS_openWrite(fname)); +} /* PHYSFSRWOPS_openWrite */ + + +SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname) +{ + return create_rwops(PHYSFS_openAppend(fname)); +} /* PHYSFSRWOPS_openAppend */ + + +/* end of physfsrwops.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/extras/physfsrwops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/extras/physfsrwops.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,88 @@ +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + */ + +#ifndef _INCLUDE_PHYSFSRWOPS_H_ +#define _INCLUDE_PHYSFSRWOPS_H_ + +#include "physfs.h" +#include "SDL.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Open a platform-independent filename for reading, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openRead(const char *fname); + +/** + * Open a platform-independent filename for writing, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname); + +/** + * Open a platform-independent filename for appending, and make it accessible + * via an SDL_RWops structure. The file will be closed in PhysicsFS when the + * RWops is closed. PhysicsFS should be configured to your liking before + * opening files through this method. + * + * @param filename File to open in platform-independent notation. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname); + +/** + * Make a SDL_RWops from an existing PhysicsFS file handle. You should + * dispose of any references to the handle after successful creation of + * the RWops. The actual PhysicsFS handle will be destroyed when the + * RWops is closed. + * + * @param handle a valid PhysicsFS file handle. + * @return A valid SDL_RWops structure on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_File *handle); + +#ifdef __cplusplus +} +#endif + +#endif /* include-once blocker */ + +/* end of physfsrwops.h ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_dir.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_dir.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,201 @@ +/* + * Standard directory I/O support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +/* There's no PHYSFS_Io interface here. Use __PHYSFS_createNativeIo(). */ + + + +static char *cvtToDependent(const char *prepend, const char *path, char *buf) +{ + BAIL_IF_MACRO(buf == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + sprintf(buf, "%s%s", prepend ? prepend : "", path); + + if (__PHYSFS_platformDirSeparator != '/') + { + char *p; + for (p = strchr(buf, '/'); p != NULL; p = strchr(p + 1, '/')) + *p = __PHYSFS_platformDirSeparator; + } /* if */ + + return buf; +} /* cvtToDependent */ + + +#define CVT_TO_DEPENDENT(buf, pre, dir) { \ + const size_t len = ((pre) ? strlen((char *) pre) : 0) + strlen(dir) + 1; \ + buf = cvtToDependent((char*)pre,dir,(char*)__PHYSFS_smallAlloc(len)); \ +} + + + +static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_Stat st; + const char dirsep = __PHYSFS_platformDirSeparator; + char *retval = NULL; + const size_t namelen = strlen(name); + const size_t seplen = 1; + int exists = 0; + + assert(io == NULL); /* shouldn't create an Io for these. */ + BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &exists, &st), ERRPASS, NULL); + if (st.filetype != PHYSFS_FILETYPE_DIRECTORY) + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); + + retval = allocator.Malloc(namelen + seplen + 1); + BAIL_IF_MACRO(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + strcpy(retval, name); + + /* make sure there's a dir separator at the end of the string */ + if (retval[namelen - 1] != dirsep) + { + retval[namelen] = dirsep; + retval[namelen + 1] = '\0'; + } /* if */ + + return retval; +} /* DIR_openArchive */ + + +static void DIR_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + char *d; + + CVT_TO_DEPENDENT(d, opaque, dname); + if (d != NULL) + { + __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb, + origdir, callbackdata); + __PHYSFS_smallFree(d); + } /* if */ +} /* DIR_enumerateFiles */ + + +static PHYSFS_Io *doOpen(PHYSFS_Dir *opaque, const char *name, + const int mode, int *fileExists) +{ + char *f; + PHYSFS_Io *io = NULL; + int existtmp = 0; + + CVT_TO_DEPENDENT(f, opaque, name); + BAIL_IF_MACRO(!f, ERRPASS, NULL); + + if (fileExists == NULL) + fileExists = &existtmp; + + io = __PHYSFS_createNativeIo(f, mode); + if (io == NULL) + { + const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode(); + PHYSFS_Stat statbuf; + __PHYSFS_platformStat(f, fileExists, &statbuf); + __PHYSFS_setError(err); + } /* if */ + else + { + *fileExists = 1; + } /* else */ + + __PHYSFS_smallFree(f); + + return io; +} /* doOpen */ + + +static PHYSFS_Io *DIR_openRead(PHYSFS_Dir *opaque, const char *fnm, int *exist) +{ + return doOpen(opaque, fnm, 'r', exist); +} /* DIR_openRead */ + + +static PHYSFS_Io *DIR_openWrite(PHYSFS_Dir *opaque, const char *filename) +{ + return doOpen(opaque, filename, 'w', NULL); +} /* DIR_openWrite */ + + +static PHYSFS_Io *DIR_openAppend(PHYSFS_Dir *opaque, const char *filename) +{ + return doOpen(opaque, filename, 'a', NULL); +} /* DIR_openAppend */ + + +static int DIR_remove(PHYSFS_Dir *opaque, const char *name) +{ + int retval; + char *f; + + CVT_TO_DEPENDENT(f, opaque, name); + BAIL_IF_MACRO(!f, ERRPASS, 0); + retval = __PHYSFS_platformDelete(f); + __PHYSFS_smallFree(f); + return retval; +} /* DIR_remove */ + + +static int DIR_mkdir(PHYSFS_Dir *opaque, const char *name) +{ + int retval; + char *f; + + CVT_TO_DEPENDENT(f, opaque, name); + BAIL_IF_MACRO(!f, ERRPASS, 0); + retval = __PHYSFS_platformMkDir(f); + __PHYSFS_smallFree(f); + return retval; +} /* DIR_mkdir */ + + +static void DIR_closeArchive(PHYSFS_Dir *opaque) +{ + allocator.Free(opaque); +} /* DIR_closeArchive */ + + +static int DIR_stat(PHYSFS_Dir *opaque, const char *name, + int *exists, PHYSFS_Stat *stat) +{ + int retval = 0; + char *d; + + CVT_TO_DEPENDENT(d, opaque, name); + BAIL_IF_MACRO(!d, ERRPASS, 0); + retval = __PHYSFS_platformStat(d, exists, stat); + __PHYSFS_smallFree(d); + return retval; +} /* DIR_stat */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_DIR = +{ + { + "", + "Non-archive, direct filesystem I/O", + "Ryan C. Gordon ", + "http://icculus.org/physfs/", + }, + DIR_openArchive, /* openArchive() method */ + DIR_enumerateFiles, /* enumerateFiles() method */ + DIR_openRead, /* openRead() method */ + DIR_openWrite, /* openWrite() method */ + DIR_openAppend, /* openAppend() method */ + DIR_remove, /* remove() method */ + DIR_mkdir, /* mkdir() method */ + DIR_closeArchive, /* closeArchive() method */ + DIR_stat /* stat() method */ +}; + +/* end of dir.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_grp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_grp.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,110 @@ +/* + * GRP support routines for PhysicsFS. + * + * This driver handles BUILD engine archives ("groupfiles"). This format + * (but not this driver) was put together by Ken Silverman. + * + * The format is simple enough. In Ken's words: + * + * What's the .GRP file format? + * + * The ".grp" file format is just a collection of a lot of files stored + * into 1 big one. I tried to make the format as simple as possible: The + * first 12 bytes contains my name, "KenSilverman". The next 4 bytes is + * the number of files that were compacted into the group file. Then for + * each file, there is a 16 byte structure, where the first 12 bytes are + * the filename, and the last 4 bytes are the file's size. The rest of + * the group file is just the raw data packed one after the other in the + * same order as the list of files. + * + * (That info is from http://www.advsys.net/ken/build.htm ...) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_GRP + +static UNPKentry *grpLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) +{ + PHYSFS_uint32 location = 16; /* sizeof sig. */ + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + char *ptr = NULL; + + entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); + BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + location += (16 * fileCount); + + for (entry = entries; fileCount > 0; fileCount--, entry++) + { + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 12), ERRPASS, failed); + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed); + entry->name[12] = '\0'; /* name isn't null-terminated in file. */ + if ((ptr = strchr(entry->name, ' ')) != NULL) + *ptr = '\0'; /* trim extra spaces. */ + + entry->size = PHYSFS_swapULE32(entry->size); + entry->startPos = location; + location += entry->size; + } /* for */ + + return entries; + +failed: + allocator.Free(entries); + return NULL; +} /* grpLoadEntries */ + + +static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint8 buf[12]; + PHYSFS_uint32 count = 0; + UNPKentry *entries = NULL; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL); + if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0) + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL); + count = PHYSFS_swapULE32(count); + + entries = grpLoadEntries(io, count); + BAIL_IF_MACRO(!entries, ERRPASS, NULL); + return UNPK_openArchive(io, entries, count); +} /* GRP_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_GRP = +{ + { + "GRP", + "Build engine Groupfile format", + "Ryan C. Gordon ", + "http://icculus.org/physfs/", + }, + GRP_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_GRP */ + +/* end of grp.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_hog.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_hog.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,116 @@ +/* + * HOG support routines for PhysicsFS. + * + * This driver handles Descent I/II HOG archives. + * + * The format is very simple: + * + * The file always starts with the 3-byte signature "DHF" (Descent + * HOG file). After that the files of a HOG are just attached after + * another, divided by a 17 bytes header, which specifies the name + * and length (in bytes) of the forthcoming file! So you just read + * the header with its information of how big the following file is, + * and then skip exact that number of bytes to get to the next file + * in that HOG. + * + * char sig[3] = {'D', 'H', 'F'}; // "DHF"=Descent HOG File + * + * struct { + * char file_name[13]; // Filename, padded to 13 bytes with 0s + * int file_size; // filesize in bytes + * char data[file_size]; // The file data + * } FILE_STRUCT; // Repeated until the end of the file. + * + * (That info is from http://www.descent2.com/ddn/specs/hog/) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Bradley Bell. + * Based on grp.c by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_HOG + +static UNPKentry *hogLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 *_entCount) +{ + const PHYSFS_uint64 iolen = io->length(io); + PHYSFS_uint32 entCount = 0; + void *ptr = NULL; + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + PHYSFS_uint32 size = 0; + PHYSFS_uint32 pos = 3; + + while (pos < iolen) + { + entCount++; + ptr = allocator.Realloc(ptr, sizeof (UNPKentry) * entCount); + GOTO_IF_MACRO(ptr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, failed); + entries = (UNPKentry *) ptr; + entry = &entries[entCount-1]; + + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 13), ERRPASS, failed); + pos += 13; + GOTO_IF_MACRO(!__PHYSFS_readAll(io, &size, 4), ERRPASS, failed); + pos += 4; + + entry->size = PHYSFS_swapULE32(size); + entry->startPos = pos; + pos += size; + + /* skip over entry */ + GOTO_IF_MACRO(!io->seek(io, pos), ERRPASS, failed); + } /* while */ + + *_entCount = entCount; + return entries; + +failed: + allocator.Free(entries); + return NULL; +} /* hogLoadEntries */ + + +static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint8 buf[3]; + PHYSFS_uint32 count = 0; + UNPKentry *entries = NULL; + + assert(io != NULL); /* shouldn't ever happen. */ + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 3), ERRPASS, NULL); + BAIL_IF_MACRO(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL); + + entries = hogLoadEntries(io, &count); + BAIL_IF_MACRO(!entries, ERRPASS, NULL); + return UNPK_openArchive(io, entries, count); +} /* HOG_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_HOG = +{ + { + "HOG", + "Descent I/II HOG file format", + "Bradley Bell ", + "http://icculus.org/physfs/", + }, + HOG_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_HOG */ + +/* end of hog.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_iso9660.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_iso9660.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,969 @@ +/* + * ISO9660 support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Christoph Nelles. + */ + +/* !!! FIXME: this file needs Ryanification. */ + +/* + * Handles CD-ROM disk images (and raw CD-ROM devices). + * + * Not supported: + * - RockRidge + * - Non 2048 Sectors + * - UDF + * + * Deviations from the standard + * - Ignores mandatory sort order + * - Allows various invalid file names + * + * Problems + * - Ambiguities in the standard + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_ISO9660 + +#include + +/* cache files smaller than this completely in memory */ +#define ISO9660_FULLCACHEMAXSIZE 2048 + +/* !!! FIXME: this is going to cause trouble. */ +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary */ + +/* This is the format as defined by the standard +typedef struct +{ + PHYSFS_uint32 lsb; + PHYSFS_uint32 msb; +} ISOBB32bit; // 32byte Both Byte type, means the value first in LSB then in MSB + +typedef struct +{ + PHYSFS_uint16 lsb; + PHYSFS_uint16 msb; +} ISOBB16bit; // 16byte Both Byte type, means the value first in LSB then in MSB +*/ + +/* define better ones to simplify coding (less if's) */ +#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN +#define ISOBB32bit(name) PHYSFS_uint32 name; PHYSFS_uint32 __dummy_##name; +#define ISOBB16bit(name) PHYSFS_uint16 name; PHYSFS_uint16 __dummy_##name; +#else +#define ISOBB32bit(name) PHYSFS_uint32 __dummy_##name; PHYSFS_uint32 name; +#define ISOBB16bit(name) PHYSFS_uint16 __dummy_##name; PHYSFS_uint16 name; +#endif + +typedef struct +{ + char year[4]; + char month[2]; + char day[2]; + char hour[2]; + char minute[2]; + char second[2]; + char centisec[2]; + PHYSFS_sint8 offset; /* in 15min from GMT */ +} ISO9660VolumeTimestamp; + +typedef struct +{ + PHYSFS_uint8 year; + PHYSFS_uint8 month; + PHYSFS_uint8 day; + PHYSFS_uint8 hour; + PHYSFS_uint8 minute; + PHYSFS_uint8 second; + PHYSFS_sint8 offset; +} ISO9660FileTimestamp; + +typedef struct +{ + unsigned existence:1; + unsigned directory:1; + unsigned associated_file:1; + unsigned record:1; + unsigned protection:1; + unsigned reserved:2; + unsigned multiextent:1; +} ISO9660FileFlags; + +typedef struct +{ + PHYSFS_uint8 length; + PHYSFS_uint8 attribute_length; + ISOBB32bit(extent_location) + ISOBB32bit(data_length) + ISO9660FileTimestamp timestamp; + ISO9660FileFlags file_flags; + PHYSFS_uint8 file_unit_size; + PHYSFS_uint8 gap_size; + ISOBB16bit(vol_seq_no) + PHYSFS_uint8 len_fi; + char unused; +} ISO9660RootDirectoryRecord; + +/* this structure is combined for all Volume descriptor types */ +typedef struct +{ + PHYSFS_uint8 type; + char identifier[5]; + PHYSFS_uint8 version; + PHYSFS_uint8 flags; + char system_identifier[32]; + char volume_identifier[32]; + char unused2[8]; + ISOBB32bit(space_size) + PHYSFS_uint8 escape_sequences[32]; + ISOBB16bit(vol_set_size) + ISOBB16bit(vol_seq_no) + ISOBB16bit(block_size) + ISOBB32bit(path_table_size) +/* PHYSFS_uint32 path_table_start_lsb; // why didn't they use both byte type? + PHYSFS_uint32 opt_path_table_start_lsb; + PHYSFS_uint32 path_table_start_msb; + PHYSFS_uint32 opt_path_table_start_msb;*/ +#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN + PHYSFS_uint32 path_table_start; + PHYSFS_uint32 opt_path_table_start; + PHYSFS_uint32 unused6; + PHYSFS_uint32 unused7; +#else + PHYSFS_uint32 unused6; + PHYSFS_uint32 unused7; + PHYSFS_uint32 path_table_start; + PHYSFS_uint32 opt_path_table_start; +#endif + ISO9660RootDirectoryRecord rootdirectory; + char set_identifier[128]; + char publisher_identifier[128]; + char preparer_identifer[128]; + char application_identifier[128]; + char copyright_file_identifier[37]; + char abstract_file_identifier[37]; + char bibliographic_file_identifier[37]; + ISO9660VolumeTimestamp creation_timestamp; + ISO9660VolumeTimestamp modification_timestamp; + ISO9660VolumeTimestamp expiration_timestamp; + ISO9660VolumeTimestamp effective_timestamp; + PHYSFS_uint8 file_structure_version; + char unused4; + char application_use[512]; + char unused5[653]; +} ISO9660VolumeDescriptor; + +typedef struct +{ + PHYSFS_uint8 recordlen; + PHYSFS_uint8 extattributelen; + ISOBB32bit(extentpos) + ISOBB32bit(datalen) + ISO9660FileTimestamp recordtime; + ISO9660FileFlags flags; + PHYSFS_uint8 file_unit_size; + PHYSFS_uint8 interleave_gap; + ISOBB16bit(volseqno) + PHYSFS_uint8 filenamelen; + char filename[222]; /* This is not exact, but makes reading easier */ +} ISO9660FileDescriptor; + +typedef struct +{ + ISOBB16bit(owner) + ISOBB16bit(group) + PHYSFS_uint16 flags; /* not implemented*/ + ISO9660VolumeTimestamp create_time; /* yes, not file timestamp */ + ISO9660VolumeTimestamp mod_time; + ISO9660VolumeTimestamp expire_time; + ISO9660VolumeTimestamp effective_time; + PHYSFS_uint8 record_format; + PHYSFS_uint8 record_attributes; + ISOBB16bit(record_len) + char system_identifier[32]; + char system_use[64]; + PHYSFS_uint8 version; + ISOBB16bit(escape_len) + char reserved[64]; + /** further fields not implemented */ +} ISO9660ExtAttributeRec; + +#pragma pack(pop) /* restore original alignment from stack */ + +typedef struct +{ + PHYSFS_Io *io; + PHYSFS_uint32 rootdirstart; + PHYSFS_uint32 rootdirsize; + PHYSFS_uint64 currpos; + int isjoliet; + char *path; + void *mutex; +} ISO9660Handle; + + +typedef struct __ISO9660FileHandle +{ + PHYSFS_sint64 filesize; + PHYSFS_uint64 currpos; + PHYSFS_uint64 startblock; + ISO9660Handle *isohandle; + PHYSFS_uint32 (*read) (struct __ISO9660FileHandle *filehandle, void *buffer, + PHYSFS_uint64 len); + int (*seek)(struct __ISO9660FileHandle *filehandle, PHYSFS_sint64 offset); + void (*close)(struct __ISO9660FileHandle *filehandle); + /* !!! FIXME: anonymouse union is going to cause problems. */ + union + { + /* !!! FIXME: just use a memory PHYSFS_Io here, unify all this code. */ + char *cacheddata; /* data of file when cached */ + PHYSFS_Io *io; /* handle to separate opened file */ + }; +} ISO9660FileHandle; + +/******************************************************************************* + * Time conversion functions + ******************************************************************************/ + +static PHYSFS_sint64 iso_mktime(ISO9660FileTimestamp *timestamp) +{ + struct tm tm; + tm.tm_year = timestamp->year; + tm.tm_mon = timestamp->month - 1; + tm.tm_mday = timestamp->day; + tm.tm_hour = timestamp->hour; + tm.tm_min = timestamp->minute; + tm.tm_sec = timestamp->second; + /* Ignore GMT offset for now... */ + return mktime(&tm); +} /* iso_mktime */ + +static int iso_atoi2(char *text) +{ + return ((text[0] - 40) * 10) + (text[1] - 40); +} /* iso_atoi2 */ + +static int iso_atoi4(char *text) +{ + return ((text[0] - 40) * 1000) + ((text[1] - 40) * 100) + + ((text[2] - 40) * 10) + (text[3] - 40); +} /* iso_atoi4 */ + +static PHYSFS_sint64 iso_volume_mktime(ISO9660VolumeTimestamp *timestamp) +{ + struct tm tm; + tm.tm_year = iso_atoi4(timestamp->year); + tm.tm_mon = iso_atoi2(timestamp->month) - 1; + tm.tm_mday = iso_atoi2(timestamp->day); + tm.tm_hour = iso_atoi2(timestamp->hour); + tm.tm_min = iso_atoi2(timestamp->minute); + tm.tm_sec = iso_atoi2(timestamp->second); + /* this allows values outside the range of a unix timestamp... sanitize them */ + PHYSFS_sint64 value = mktime(&tm); + return value == -1 ? 0 : value; +} /* iso_volume_mktime */ + +/******************************************************************************* + * Filename extraction + ******************************************************************************/ + +static int iso_extractfilenameISO(ISO9660FileDescriptor *descriptor, + char *filename, int *version) +{ + *filename = '\0'; + if (descriptor->flags.directory) + { + strncpy(filename, descriptor->filename, descriptor->filenamelen); + filename[descriptor->filenamelen] = '\0'; + *version = 0; + } /* if */ + else + { + /* find last SEPARATOR2 */ + int pos = 0; + int lastfound = -1; + for(;pos < descriptor->filenamelen; pos++) + if (descriptor->filename[pos] == ';') + lastfound = pos; + BAIL_IF_MACRO(lastfound < 1, PHYSFS_ERR_NO_SUCH_PATH /* !!! FIXME: PHYSFS_ERR_BAD_FILENAME */, -1); + BAIL_IF_MACRO(lastfound == (descriptor->filenamelen -1), PHYSFS_ERR_NO_SUCH_PATH /* !!! PHYSFS_ERR_BAD_FILENAME */, -1); + strncpy(filename, descriptor->filename, lastfound); + if (filename[lastfound - 1] == '.') + filename[lastfound - 1] = '\0'; /* consume trailing ., as done in all implementations */ + else + filename[lastfound] = '\0'; + *version = atoi(descriptor->filename + lastfound); + } /* else */ + + return 0; +} /* iso_extractfilenameISO */ + + +static int iso_extractfilenameUCS2(ISO9660FileDescriptor *descriptor, + char *filename, int *version) +{ + PHYSFS_uint16 tmp[128]; + PHYSFS_uint16 *src; + int len; + + *filename = '\0'; + *version = 1; /* Joliet does not have versions.. at least not on my images */ + + src = (PHYSFS_uint16*) descriptor->filename; + len = descriptor->filenamelen / 2; + tmp[len] = 0; + + while(len--) + tmp[len] = PHYSFS_swapUBE16(src[len]); + + PHYSFS_utf8FromUcs2(tmp, filename, 255); + + return 0; +} /* iso_extractfilenameUCS2 */ + + +static int iso_extractfilename(ISO9660Handle *handle, + ISO9660FileDescriptor *descriptor, char *filename,int *version) +{ + if (handle->isjoliet) + return iso_extractfilenameUCS2(descriptor, filename, version); + else + return iso_extractfilenameISO(descriptor, filename, version); +} /* iso_extractfilename */ + +/******************************************************************************* + * Basic image read functions + ******************************************************************************/ + +static int iso_readimage(ISO9660Handle *handle, PHYSFS_uint64 where, + void *buffer, PHYSFS_uint64 len) +{ + BAIL_IF_MACRO(!__PHYSFS_platformGrabMutex(handle->mutex), ERRPASS, -1); + int rc = -1; + if (where != handle->currpos) + GOTO_IF_MACRO(!handle->io->seek(handle->io,where), ERRPASS, unlockme); + rc = handle->io->read(handle->io, buffer, len); + if (rc == -1) + { + handle->currpos = (PHYSFS_uint64) -1; + goto unlockme; + } /* if */ + handle->currpos += rc; + + unlockme: + __PHYSFS_platformReleaseMutex(handle->mutex); + return rc; +} /* iso_readimage */ + + +static PHYSFS_sint64 iso_readfiledescriptor(ISO9660Handle *handle, + PHYSFS_uint64 where, + ISO9660FileDescriptor *descriptor) +{ + PHYSFS_sint64 rc = iso_readimage(handle, where, descriptor, + sizeof (descriptor->recordlen)); + BAIL_IF_MACRO(rc == -1, ERRPASS, -1); + BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1); + + if (descriptor->recordlen == 0) + return 0; /* fill bytes at the end of a sector */ + + rc = iso_readimage(handle, where + 1, &descriptor->extattributelen, + descriptor->recordlen - sizeof(descriptor->recordlen)); + BAIL_IF_MACRO(rc == -1, ERRPASS, -1); + BAIL_IF_MACRO(rc != 1, PHYSFS_ERR_CORRUPT, -1); + + return 0; +} /* iso_readfiledescriptor */ + +static void iso_extractsubpath(char *path, char **subpath) +{ + *subpath = strchr(path,'/'); + if (*subpath != 0) + { + **subpath = 0; + *subpath +=1; + } /* if */ +} /* iso_extractsubpath */ + +/* + * Don't use path tables, they are not necessarily faster, but more complicated + * to implement as they store only directories and not files, so searching for + * a file needs to branch to the directory extent sooner or later. + */ +static int iso_find_dir_entry(ISO9660Handle *handle,const char *path, + ISO9660FileDescriptor *descriptor, int *exists) +{ + char *subpath = 0; + PHYSFS_uint64 readpos, end_of_dir; + char filename[255]; + char pathcopy[256]; + char *mypath; + int version = 0; + + strcpy(pathcopy, path); + mypath = pathcopy; + *exists = 0; + + readpos = handle->rootdirstart; + end_of_dir = handle->rootdirstart + handle->rootdirsize; + iso_extractsubpath(mypath, &subpath); + while (1) + { + BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, descriptor), ERRPASS, -1); + + /* recordlen = 0 -> no more entries or fill entry */ + if (!descriptor->recordlen) + { + /* if we are in the last sector of the directory & it's 0 -> end */ + if ((end_of_dir - 2048) <= (readpos -1)) + break; /* finished */ + + /* else skip to the next sector & continue; */ + readpos = (((readpos - 1) / 2048) + 1) * 2048; + continue; + } /* if */ + + readpos += descriptor->recordlen; + if (descriptor->filenamelen == 1 && (descriptor->filename[0] == 0 + || descriptor->filename[0] == 1)) + continue; /* special ones, ignore */ + + BAIL_IF_MACRO( + iso_extractfilename(handle, descriptor, filename, &version), + ERRPASS, -1); + + if (strcmp(filename, mypath) == 0) + { + if ( (subpath == 0) || (subpath[0] == 0) ) + { + *exists = 1; + return 0; /* no subpaths left and we found the entry */ + } /* if */ + + if (descriptor->flags.directory) + { + /* shorten the path to the subpath */ + mypath = subpath; + iso_extractsubpath(mypath, &subpath); + /* gosub to the new directory extent */ + readpos = descriptor->extentpos * 2048; + end_of_dir = readpos + descriptor->datalen; + } /* if */ + else + { + /* we're at a file but have a remaining subpath -> no match */ + return 0; + } /* else */ + } /* if */ + } /* while */ + + return 0; +} /* iso_find_dir_entry */ + + +static int iso_read_ext_attributes(ISO9660Handle *handle, int block, + ISO9660ExtAttributeRec *attributes) +{ + return iso_readimage(handle, block * 2048, attributes, + sizeof(ISO9660ExtAttributeRec)); +} /* iso_read_ext_attributes */ + + +static int ISO9660_flush(PHYSFS_Io *io) { return 1; /* no write support. */ } + +static PHYSFS_Io *ISO9660_duplicate(PHYSFS_Io *_io) +{ + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); /* !!! FIXME: write me. */ +} /* ISO9660_duplicate */ + + +static void ISO9660_destroy(PHYSFS_Io *io) +{ + ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque; + fhandle->close(fhandle); + allocator.Free(io); +} /* ISO9660_destroy */ + + +static PHYSFS_sint64 ISO9660_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) +{ + ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque; + return fhandle->read(fhandle, buf, len); +} /* ISO9660_read */ + + +static PHYSFS_sint64 ISO9660_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 l) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1); +} /* ISO9660_write */ + + +static PHYSFS_sint64 ISO9660_tell(PHYSFS_Io *io) +{ + return ((ISO9660FileHandle*) io->opaque)->currpos; +} /* ISO9660_tell */ + + +static int ISO9660_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + ISO9660FileHandle *fhandle = (ISO9660FileHandle*) io->opaque; + return fhandle->seek(fhandle, offset); +} /* ISO9660_seek */ + + +static PHYSFS_sint64 ISO9660_length(PHYSFS_Io *io) +{ + return ((ISO9660FileHandle*) io->opaque)->filesize; +} /* ISO9660_length */ + + +static const PHYSFS_Io ISO9660_Io = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + ISO9660_read, + ISO9660_write, + ISO9660_seek, + ISO9660_tell, + ISO9660_length, + ISO9660_duplicate, + ISO9660_flush, + ISO9660_destroy +}; + + +/******************************************************************************* + * Archive management functions + ******************************************************************************/ + +static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting) +{ + char magicnumber[6]; + ISO9660Handle *handle; + int founddescriptor = 0; + int foundjoliet = 0; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + + /* Skip system area to magic number in Volume descriptor */ + BAIL_IF_MACRO(!io->seek(io, 32769), ERRPASS, NULL); + BAIL_IF_MACRO(!io->read(io, magicnumber, 5) != 5, ERRPASS, NULL); + if (memcmp(magicnumber, "CD001", 6) != 0) + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); + + handle = allocator.Malloc(sizeof(ISO9660Handle)); + GOTO_IF_MACRO(!handle, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup); + handle->path = 0; + handle->mutex= 0; + handle->io = NULL; + + handle->path = allocator.Malloc(strlen(filename) + 1); + GOTO_IF_MACRO(!handle->path, PHYSFS_ERR_OUT_OF_MEMORY, errorcleanup); + strcpy(handle->path, filename); + + handle->mutex = __PHYSFS_platformCreateMutex(); + GOTO_IF_MACRO(!handle->mutex, ERRPASS, errorcleanup); + + handle->io = io; + + /* seek Primary Volume Descriptor */ + GOTO_IF_MACRO(!io->seek(io, 32768), PHYSFS_ERR_IO, errorcleanup); + + while (1) + { + ISO9660VolumeDescriptor descriptor; + GOTO_IF_MACRO(io->read(io, &descriptor, sizeof(ISO9660VolumeDescriptor)) != sizeof(ISO9660VolumeDescriptor), PHYSFS_ERR_IO, errorcleanup); + GOTO_IF_MACRO(strncmp(descriptor.identifier, "CD001", 5) != 0, PHYSFS_ERR_UNSUPPORTED, errorcleanup); + + if (descriptor.type == 255) + { + /* type 255 terminates the volume descriptor list */ + if (founddescriptor) + return handle; /* ok, we've found one volume descriptor */ + else + GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup); + } /* if */ + if (descriptor.type == 1 && !founddescriptor) + { + handle->currpos = io->tell(io); + handle->rootdirstart = + descriptor.rootdirectory.extent_location * 2048; + handle->rootdirsize = + descriptor.rootdirectory.data_length; + handle->isjoliet = 0; + founddescriptor = 1; /* continue search for joliet */ + } /* if */ + if (descriptor.type == 2 && !foundjoliet) + { + /* check if is joliet */ + PHYSFS_uint8 *s = descriptor.escape_sequences; + int joliet = !(descriptor.flags & 1) + && (s[0] == 0x25) + && (s[1] == 0x2F) + && ((s[2] == 0x40) || (s[2] == 0x43) || (s[2] == 0x45)); + if (!joliet) + continue; + + handle->currpos = io->tell(io); + handle->rootdirstart = + descriptor.rootdirectory.extent_location * 2048; + handle->rootdirsize = + descriptor.rootdirectory.data_length; + handle->isjoliet = 1; + founddescriptor = 1; + foundjoliet = 1; + } /* if */ + } /* while */ + + GOTO_MACRO(PHYSFS_ERR_CORRUPT, errorcleanup); /* not found. */ + +errorcleanup: + if (handle) + { + if (handle->path) + allocator.Free(handle->path); + if (handle->mutex) + __PHYSFS_platformDestroyMutex(handle->mutex); + allocator.Free(handle); + } /* if */ + return NULL; +} /* ISO9660_openArchive */ + + +static void ISO9660_closeArchive(PHYSFS_Dir *opaque) +{ + ISO9660Handle *handle = (ISO9660Handle*) opaque; + handle->io->destroy(handle->io); + __PHYSFS_platformDestroyMutex(handle->mutex); + allocator.Free(handle->path); + allocator.Free(handle); +} /* ISO9660_closeArchive */ + + +/******************************************************************************* + * Read functions + ******************************************************************************/ + + +static PHYSFS_uint32 iso_file_read_mem(ISO9660FileHandle *filehandle, + void *buffer, PHYSFS_uint64 len) +{ + /* check remaining bytes & max obj which can be fetched */ + const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos; + if (bytesleft < len) + len = bytesleft; + + if (len == 0) + return 0; + + memcpy(buffer, filehandle->cacheddata + filehandle->currpos, (size_t) len); + + filehandle->currpos += len; + return (PHYSFS_uint32) len; +} /* iso_file_read_mem */ + + +static int iso_file_seek_mem(ISO9660FileHandle *fhandle, PHYSFS_sint64 offset) +{ + BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0); + + fhandle->currpos = offset; + return 0; +} /* iso_file_seek_mem */ + + +static void iso_file_close_mem(ISO9660FileHandle *fhandle) +{ + allocator.Free(fhandle->cacheddata); + allocator.Free(fhandle); +} /* iso_file_close_mem */ + + +static PHYSFS_uint32 iso_file_read_foreign(ISO9660FileHandle *filehandle, + void *buffer, PHYSFS_uint64 len) +{ + /* check remaining bytes & max obj which can be fetched */ + const PHYSFS_sint64 bytesleft = filehandle->filesize - filehandle->currpos; + if (bytesleft < len) + len = bytesleft; + + const PHYSFS_sint64 rc = filehandle->io->read(filehandle->io, buffer, len); + BAIL_IF_MACRO(rc == -1, ERRPASS, -1); + + filehandle->currpos += rc; /* i trust my internal book keeping */ + BAIL_IF_MACRO(rc < len, PHYSFS_ERR_CORRUPT, -1); + return rc; +} /* iso_file_read_foreign */ + + +static int iso_file_seek_foreign(ISO9660FileHandle *fhandle, + PHYSFS_sint64 offset) +{ + BAIL_IF_MACRO(offset < 0, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(offset >= fhandle->filesize, PHYSFS_ERR_PAST_EOF, 0); + + PHYSFS_sint64 pos = fhandle->startblock * 2048 + offset; + BAIL_IF_MACRO(!fhandle->io->seek(fhandle->io, pos), ERRPASS, -1); + + fhandle->currpos = offset; + return 0; +} /* iso_file_seek_foreign */ + + +static void iso_file_close_foreign(ISO9660FileHandle *fhandle) +{ + fhandle->io->destroy(fhandle->io); + allocator.Free(fhandle); +} /* iso_file_close_foreign */ + + +static int iso_file_open_mem(ISO9660Handle *handle, ISO9660FileHandle *fhandle) +{ + fhandle->cacheddata = allocator.Malloc(fhandle->filesize); + BAIL_IF_MACRO(!fhandle->cacheddata, PHYSFS_ERR_OUT_OF_MEMORY, -1); + int rc = iso_readimage(handle, fhandle->startblock * 2048, + fhandle->cacheddata, fhandle->filesize); + GOTO_IF_MACRO(rc < 0, ERRPASS, freemem); + GOTO_IF_MACRO(rc == 0, PHYSFS_ERR_CORRUPT, freemem); + + fhandle->read = iso_file_read_mem; + fhandle->seek = iso_file_seek_mem; + fhandle->close = iso_file_close_mem; + return 0; + +freemem: + allocator.Free(fhandle->cacheddata); + return -1; +} /* iso_file_open_mem */ + + +static int iso_file_open_foreign(ISO9660Handle *handle, + ISO9660FileHandle *fhandle) +{ + int rc; + fhandle->io = __PHYSFS_createNativeIo(handle->path, 'r'); + BAIL_IF_MACRO(!fhandle->io, ERRPASS, -1); + rc = fhandle->io->seek(fhandle->io, fhandle->startblock * 2048); + GOTO_IF_MACRO(!rc, ERRPASS, closefile); + + fhandle->read = iso_file_read_foreign; + fhandle->seek = iso_file_seek_foreign; + fhandle->close = iso_file_close_foreign; + return 0; + +closefile: + fhandle->io->destroy(fhandle->io); + return -1; +} /* iso_file_open_foreign */ + + +static PHYSFS_Io *ISO9660_openRead(PHYSFS_Dir *opaque, const char *filename, + int *exists) +{ + PHYSFS_Io *retval = NULL; + ISO9660Handle *handle = (ISO9660Handle*) opaque; + ISO9660FileHandle *fhandle; + ISO9660FileDescriptor descriptor; + int rc; + + fhandle = allocator.Malloc(sizeof(ISO9660FileHandle)); + BAIL_IF_MACRO(fhandle == 0, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + fhandle->cacheddata = 0; + + retval = allocator.Malloc(sizeof(PHYSFS_Io)); + GOTO_IF_MACRO(retval == 0, PHYSFS_ERR_OUT_OF_MEMORY, errorhandling); + + /* find file descriptor */ + rc = iso_find_dir_entry(handle, filename, &descriptor, exists); + GOTO_IF_MACRO(rc, ERRPASS, errorhandling); + GOTO_IF_MACRO(!*exists, PHYSFS_ERR_NO_SUCH_PATH, errorhandling); + + fhandle->startblock = descriptor.extentpos + descriptor.extattributelen; + fhandle->filesize = descriptor.datalen; + fhandle->currpos = 0; + fhandle->isohandle = handle; + fhandle->cacheddata = NULL; + fhandle->io = NULL; + + if (descriptor.datalen <= ISO9660_FULLCACHEMAXSIZE) + rc = iso_file_open_mem(handle, fhandle); + else + rc = iso_file_open_foreign(handle, fhandle); + GOTO_IF_MACRO(rc, ERRPASS, errorhandling); + + memcpy(retval, &ISO9660_Io, sizeof (PHYSFS_Io)); + retval->opaque = fhandle; + return retval; + +errorhandling: + if (retval) allocator.Free(retval); + if (fhandle) allocator.Free(fhandle); + return NULL; +} /* ISO9660_openRead */ + + + +/******************************************************************************* + * Information gathering functions + ******************************************************************************/ + +static void ISO9660_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, + PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + ISO9660Handle *handle = (ISO9660Handle*) opaque; + ISO9660FileDescriptor descriptor; + PHYSFS_uint64 readpos; + PHYSFS_uint64 end_of_dir; + char filename[130]; /* ISO allows 31, Joliet 128 -> 128 + 2 eol bytes */ + int version = 0; + + if (*dname == '\0') + { + readpos = handle->rootdirstart; + end_of_dir = readpos + handle->rootdirsize; + } /* if */ + else + { + printf("pfad %s\n",dname); + int exists = 0; + BAIL_IF_MACRO(iso_find_dir_entry(handle,dname, &descriptor, &exists), ERRPASS,); + BAIL_IF_MACRO(!exists, ERRPASS, ); + BAIL_IF_MACRO(!descriptor.flags.directory, ERRPASS,); + + readpos = descriptor.extentpos * 2048; + end_of_dir = readpos + descriptor.datalen; + } /* else */ + + while (1) + { + BAIL_IF_MACRO(iso_readfiledescriptor(handle, readpos, &descriptor), ERRPASS, ); + + /* recordlen = 0 -> no more entries or fill entry */ + if (!descriptor.recordlen) + { + /* if we are in the last sector of the directory & it's 0 -> end */ + if ((end_of_dir - 2048) <= (readpos -1)) + break; /* finished */ + + /* else skip to the next sector & continue; */ + readpos = (((readpos - 1) / 2048) + 1) * 2048; + continue; + } /* if */ + + readpos += descriptor.recordlen; + if (descriptor.filenamelen == 1 && (descriptor.filename[0] == 0 + || descriptor.filename[0] == 1)) + continue; /* special ones, ignore */ + + strncpy(filename,descriptor.filename,descriptor.filenamelen); + iso_extractfilename(handle, &descriptor, filename, &version); + cb(callbackdata, origdir,filename); + } /* while */ +} /* ISO9660_enumerateFiles */ + + +static int ISO9660_stat(PHYSFS_Dir *opaque, const char *name, int *exists, + PHYSFS_Stat *stat) +{ + ISO9660Handle *handle = (ISO9660Handle*) opaque; + ISO9660FileDescriptor descriptor; + ISO9660ExtAttributeRec extattr; + BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, exists), ERRPASS, -1); + if (!*exists) + return 0; + + stat->readonly = 1; + + /* try to get extended info */ + if (descriptor.extattributelen) + { + BAIL_IF_MACRO(iso_read_ext_attributes(handle, + descriptor.extentpos, &extattr), ERRPASS, -1); + stat->createtime = iso_volume_mktime(&extattr.create_time); + stat->modtime = iso_volume_mktime(&extattr.mod_time); + stat->accesstime = iso_volume_mktime(&extattr.mod_time); + } /* if */ + else + { + stat->createtime = iso_mktime(&descriptor.recordtime); + stat->modtime = iso_mktime(&descriptor.recordtime); + stat->accesstime = iso_mktime(&descriptor.recordtime); + } /* else */ + + if (descriptor.flags.directory) + { + stat->filesize = 0; + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + } /* if */ + else + { + stat->filesize = descriptor.datalen; + stat->filetype = PHYSFS_FILETYPE_REGULAR; + } /* else */ + + return 1; +} /* ISO9660_stat */ + + +/******************************************************************************* + * Not supported functions + ******************************************************************************/ + +static PHYSFS_Io *ISO9660_openWrite(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* ISO9660_openWrite */ + + +static PHYSFS_Io *ISO9660_openAppend(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* ISO9660_openAppend */ + + +static int ISO9660_remove(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* ISO9660_remove */ + + +static int ISO9660_mkdir(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* ISO9660_mkdir */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660 = +{ + { + "ISO", + "ISO9660 image file", + "Christoph Nelles ", + "http://www.evilazrael.de/", + }, + ISO9660_openArchive, /* openArchive() method */ + ISO9660_enumerateFiles, /* enumerateFiles() method */ + ISO9660_openRead, /* openRead() method */ + ISO9660_openWrite, /* openWrite() method */ + ISO9660_openAppend, /* openAppend() method */ + ISO9660_remove, /* remove() method */ + ISO9660_mkdir, /* mkdir() method */ + ISO9660_closeArchive, /* closeArchive() method */ + ISO9660_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_ISO9660 */ + +/* end of archiver_iso9660.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_lzma.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_lzma.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,701 @@ +/* + * LZMA support routines for PhysicsFS. + * + * Please see the file lzma.txt in the lzma/ directory. + * + * This file was written by Dennis Schridde, with some peeking at "7zMain.c" + * by Igor Pavlov. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_7Z + +#include "lzma/C/7zCrc.h" +#include "lzma/C/Archive/7z/7zIn.h" +#include "lzma/C/Archive/7z/7zExtract.h" + + +/* 7z internal from 7zIn.c */ +extern int TestSignatureCandidate(Byte *testBytes); + + +#ifdef _LZMA_IN_CB +# define BUFFER_SIZE (1 << 12) +#endif /* _LZMA_IN_CB */ + + +/* + * Carries filestream metadata through 7z + */ +typedef struct _FileInputStream +{ + ISzAlloc allocImp; /* Allocation implementation, used by 7z */ + ISzAlloc allocTempImp; /* Temporary allocation implementation, used by 7z */ + ISzInStream inStream; /* Input stream with read callbacks, used by 7z */ + PHYSFS_Io *io; /* Filehandle, used by read implementation */ +#ifdef _LZMA_IN_CB + Byte buffer[BUFFER_SIZE]; /* Buffer, used by read implementation */ +#endif /* _LZMA_IN_CB */ +} FileInputStream; + +/* + * In the 7z format archives are splited into blocks, those are called folders + * Set by LZMA_read() +*/ +typedef struct _LZMAfolder +{ + PHYSFS_uint32 index; /* Index of folder in archive */ + PHYSFS_uint32 references; /* Number of files using this block */ + PHYSFS_uint8 *cache; /* Cached folder */ + size_t size; /* Size of folder */ +} LZMAfolder; + +/* + * Set by LZMA_openArchive(), except folder which gets it's values + * in LZMA_read() + */ +typedef struct _LZMAarchive +{ + struct _LZMAfile *files; /* Array of files, size == archive->db.Database.NumFiles */ + LZMAfolder *folders; /* Array of folders, size == archive->db.Database.NumFolders */ + CArchiveDatabaseEx db; /* For 7z: Database */ + FileInputStream stream; /* For 7z: Input file incl. read and seek callbacks */ +} LZMAarchive; + +/* Set by LZMA_openArchive(), except offset which is set by LZMA_read() */ +typedef struct _LZMAfile +{ + PHYSFS_uint32 index; /* Index of file in archive */ + LZMAarchive *archive; /* Link to corresponding archive */ + LZMAfolder *folder; /* Link to corresponding folder */ + CFileItem *item; /* For 7z: File info, eg. name, size */ + size_t offset; /* Offset in folder */ + size_t position; /* Current "virtual" position in file */ +} LZMAfile; + + +/* Memory management implementations to be passed to 7z */ + +static void *SzAllocPhysicsFS(size_t size) +{ + return ((size == 0) ? NULL : allocator.Malloc(size)); +} /* SzAllocPhysicsFS */ + + +static void SzFreePhysicsFS(void *address) +{ + if (address != NULL) + allocator.Free(address); +} /* SzFreePhysicsFS */ + + +/* Filesystem implementations to be passed to 7z */ + +#ifdef _LZMA_IN_CB + +/* + * Read implementation, to be passed to 7z + * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly! + */ +SZ_RESULT SzFileReadImp(void *object, void **buffer, size_t maxReqSize, + size_t *processedSize) +{ + FileInputStream *s = (FileInputStream *)(object - offsetof(FileInputStream, inStream)); /* HACK! */ + PHYSFS_sint64 processedSizeLoc = 0; + + if (maxReqSize > BUFFER_SIZE) + maxReqSize = BUFFER_SIZE; + processedSizeLoc = s->io->read(s->io, s->buffer, maxReqSize); + *buffer = s->buffer; + if (processedSize != NULL) + *processedSize = (size_t) processedSizeLoc; + + return SZ_OK; +} /* SzFileReadImp */ + +#else + +/* + * Read implementation, to be passed to 7z + * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly! + */ +SZ_RESULT SzFileReadImp(void *object, void *buffer, size_t size, + size_t *processedSize) +{ + FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */ + const size_t processedSizeLoc = s->io->read(s->io, buffer, size); + if (processedSize != NULL) + *processedSize = processedSizeLoc; + return SZ_OK; +} /* SzFileReadImp */ + +#endif + +/* + * Seek implementation, to be passed to 7z + * WARNING: If the ISzInStream in 'object' is not contained in a valid FileInputStream this _will_ break horribly! + */ +SZ_RESULT SzFileSeekImp(void *object, CFileSize pos) +{ + FileInputStream *s = (FileInputStream *)((unsigned long)object - offsetof(FileInputStream, inStream)); /* HACK! */ + if (s->io->seek(s->io, (PHYSFS_uint64) pos)) + return SZ_OK; + return SZE_FAIL; +} /* SzFileSeekImp */ + + +/* + * Translate Microsoft FILETIME (used by 7zip) into UNIX timestamp + */ +static PHYSFS_sint64 lzma_filetime_to_unix_timestamp(CArchiveFileTime *ft) +{ + /* MS counts in nanoseconds ... */ + const PHYSFS_uint64 FILETIME_NANOTICKS_PER_SECOND = __PHYSFS_UI64(10000000); + /* MS likes to count seconds since 01.01.1601 ... */ + const PHYSFS_uint64 FILETIME_UNIX_DIFF = __PHYSFS_UI64(11644473600); + + PHYSFS_uint64 filetime = ft->Low | ((PHYSFS_uint64)ft->High << 32); + return filetime/FILETIME_NANOTICKS_PER_SECOND - FILETIME_UNIX_DIFF; +} /* lzma_filetime_to_unix_timestamp */ + + +/* + * Compare a file with a given name, C89 stdlib variant + * Used for sorting + */ +static int lzma_file_cmp_stdlib(const void *key, const void *object) +{ + const char *name = (const char *) key; + LZMAfile *file = (LZMAfile *) object; + return strcmp(name, file->item->Name); +} /* lzma_file_cmp_posix */ + + +/* + * Compare two files with each other based on the name + * Used for sorting + */ +static int lzma_file_cmp(void *_a, size_t one, size_t two) +{ + LZMAfile *files = (LZMAfile *) _a; + return strcmp(files[one].item->Name, files[two].item->Name); +} /* lzma_file_cmp */ + + +/* + * Swap two entries in the file array + */ +static void lzma_file_swap(void *_a, size_t one, size_t two) +{ + LZMAfile tmp; + LZMAfile *first = &(((LZMAfile *) _a)[one]); + LZMAfile *second = &(((LZMAfile *) _a)[two]); + memcpy(&tmp, first, sizeof (LZMAfile)); + memcpy(first, second, sizeof (LZMAfile)); + memcpy(second, &tmp, sizeof (LZMAfile)); +} /* lzma_file_swap */ + + +/* + * Find entry 'name' in 'archive' + */ +static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name) +{ + LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */ + + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL); + + return file; +} /* lzma_find_file */ + + +/* + * Load metadata for the file at given index + */ +static int lzma_file_init(LZMAarchive *archive, PHYSFS_uint32 fileIndex) +{ + LZMAfile *file = &archive->files[fileIndex]; + PHYSFS_uint32 folderIndex = archive->db.FileIndexToFolderIndexMap[fileIndex]; + + file->index = fileIndex; /* Store index into 7z array, since we sort our own. */ + file->archive = archive; + file->folder = (folderIndex != (PHYSFS_uint32)-1 ? &archive->folders[folderIndex] : NULL); /* Directories don't have a folder (they contain no own data...) */ + file->item = &archive->db.Database.Files[fileIndex]; /* Holds crucial data and is often referenced -> Store link */ + file->position = 0; + file->offset = 0; /* Offset will be set by LZMA_read() */ + + return 1; +} /* lzma_load_file */ + + +/* + * Load metadata for all files + */ +static int lzma_files_init(LZMAarchive *archive) +{ + PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles; + + for (fileIndex = 0; fileIndex < numFiles; fileIndex++ ) + { + if (!lzma_file_init(archive, fileIndex)) + { + return 0; /* FALSE on failure */ + } + } /* for */ + + __PHYSFS_sort(archive->files, (size_t) numFiles, lzma_file_cmp, lzma_file_swap); + + return 1; +} /* lzma_load_files */ + + +/* + * Initialise specified archive + */ +static void lzma_archive_init(LZMAarchive *archive) +{ + memset(archive, 0, sizeof(*archive)); + + /* Prepare callbacks for 7z */ + archive->stream.inStream.Read = SzFileReadImp; + archive->stream.inStream.Seek = SzFileSeekImp; + + archive->stream.allocImp.Alloc = SzAllocPhysicsFS; + archive->stream.allocImp.Free = SzFreePhysicsFS; + + archive->stream.allocTempImp.Alloc = SzAllocPhysicsFS; + archive->stream.allocTempImp.Free = SzFreePhysicsFS; +} + + +/* + * Deinitialise archive + */ +static void lzma_archive_exit(LZMAarchive *archive) +{ + /* Free arrays */ + allocator.Free(archive->folders); + allocator.Free(archive->files); + allocator.Free(archive); +} + +/* + * Wrap all 7z calls in this, so the physfs error state is set appropriately. + */ +static int lzma_err(SZ_RESULT rc) +{ + switch (rc) + { + case SZ_OK: /* Same as LZMA_RESULT_OK */ + break; + case SZE_DATA_ERROR: /* Same as LZMA_RESULT_DATA_ERROR */ + __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /*!!!FIXME: was "PHYSFS_ERR_DATA_ERROR" */ + break; + case SZE_OUTOFMEMORY: + __PHYSFS_setError(PHYSFS_ERR_OUT_OF_MEMORY); + break; + case SZE_CRC_ERROR: + __PHYSFS_setError(PHYSFS_ERR_CORRUPT); + break; + case SZE_NOTIMPL: + __PHYSFS_setError(PHYSFS_ERR_UNSUPPORTED); + break; + case SZE_FAIL: + __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* !!! FIXME: right? */ + break; + case SZE_ARCHIVE_ERROR: + __PHYSFS_setError(PHYSFS_ERR_CORRUPT); /* !!! FIXME: right? */ + break; + default: + __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); + } /* switch */ + + return rc; +} /* lzma_err */ + + +static PHYSFS_sint64 LZMA_read(PHYSFS_Io *io, void *outBuf, PHYSFS_uint64 len) +{ + LZMAfile *file = (LZMAfile *) io->opaque; + + size_t wantedSize = (size_t) len; + const size_t remainingSize = file->item->Size - file->position; + size_t fileSize = 0; + + BAIL_IF_MACRO(wantedSize == 0, ERRPASS, 0); /* quick rejection. */ + BAIL_IF_MACRO(remainingSize == 0, PHYSFS_ERR_PAST_EOF, 0); + + if (wantedSize > remainingSize) + wantedSize = remainingSize; + + /* Only decompress the folder if it is not already cached */ + if (file->folder->cache == NULL) + { + const int rc = lzma_err(SzExtract( + &file->archive->stream.inStream, /* compressed data */ + &file->archive->db, /* 7z's database, containing everything */ + file->index, /* Index into database arrays */ + /* Index of cached folder, will be changed by SzExtract */ + &file->folder->index, + /* Cache for decompressed folder, allocated/freed by SzExtract */ + &file->folder->cache, + /* Size of cache, will be changed by SzExtract */ + &file->folder->size, + /* Offset of this file inside the cache, set by SzExtract */ + &file->offset, + &fileSize, /* Size of this file */ + &file->archive->stream.allocImp, + &file->archive->stream.allocTempImp)); + + if (rc != SZ_OK) + return -1; + } /* if */ + + /* Copy wanted bytes over from cache to outBuf */ + memcpy(outBuf, (file->folder->cache + file->offset + file->position), + wantedSize); + file->position += wantedSize; /* Increase virtual position */ + + return wantedSize; +} /* LZMA_read */ + + +static PHYSFS_sint64 LZMA_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1); +} /* LZMA_write */ + + +static PHYSFS_sint64 LZMA_tell(PHYSFS_Io *io) +{ + LZMAfile *file = (LZMAfile *) io->opaque; + return file->position; +} /* LZMA_tell */ + + +static int LZMA_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + LZMAfile *file = (LZMAfile *) io->opaque; + + BAIL_IF_MACRO(offset > file->item->Size, PHYSFS_ERR_PAST_EOF, 0); + + file->position = offset; /* We only use a virtual position... */ + + return 1; +} /* LZMA_seek */ + + +static PHYSFS_sint64 LZMA_length(PHYSFS_Io *io) +{ + const LZMAfile *file = (LZMAfile *) io->opaque; + return (file->item->Size); +} /* LZMA_length */ + + +static PHYSFS_Io *LZMA_duplicate(PHYSFS_Io *_io) +{ + /* !!! FIXME: this archiver needs to be reworked to allow multiple + * !!! FIXME: opens before we worry about duplication. */ + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); +} /* LZMA_duplicate */ + + +static int LZMA_flush(PHYSFS_Io *io) { return 1; /* no write support. */ } + + +static void LZMA_destroy(PHYSFS_Io *io) +{ + LZMAfile *file = (LZMAfile *) io->opaque; + + if (file->folder != NULL) + { + /* Only decrease refcount if someone actually requested this file... Prevents from overflows and close-on-open... */ + if (file->folder->references > 0) + file->folder->references--; + if (file->folder->references == 0) + { + /* Free the cache which might have been allocated by LZMA_read() */ + allocator.Free(file->folder->cache); + file->folder->cache = NULL; + } + /* !!! FIXME: we don't free (file) or (file->folder)?! */ + } /* if */ +} /* LZMA_destroy */ + + +static const PHYSFS_Io LZMA_Io = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + LZMA_read, + LZMA_write, + LZMA_seek, + LZMA_tell, + LZMA_length, + LZMA_duplicate, + LZMA_flush, + LZMA_destroy +}; + + +static void *LZMA_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint8 sig[k7zSignatureSize]; + size_t len = 0; + LZMAarchive *archive = NULL; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + + if (io->read(io, sig, k7zSignatureSize) != k7zSignatureSize) + return 0; + BAIL_IF_MACRO(!TestSignatureCandidate(sig), PHYSFS_ERR_UNSUPPORTED, NULL); + BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL); + + archive = (LZMAarchive *) allocator.Malloc(sizeof (LZMAarchive)); + BAIL_IF_MACRO(archive == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + lzma_archive_init(archive); + archive->stream.io = io; + + CrcGenerateTable(); + SzArDbExInit(&archive->db); + if (lzma_err(SzArchiveOpen(&archive->stream.inStream, + &archive->db, + &archive->stream.allocImp, + &archive->stream.allocTempImp)) != SZ_OK) + { + SzArDbExFree(&archive->db, SzFreePhysicsFS); + lzma_archive_exit(archive); + return NULL; /* Error is set by lzma_err! */ + } /* if */ + + len = archive->db.Database.NumFiles * sizeof (LZMAfile); + archive->files = (LZMAfile *) allocator.Malloc(len); + if (archive->files == NULL) + { + SzArDbExFree(&archive->db, SzFreePhysicsFS); + lzma_archive_exit(archive); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } + + /* + * Init with 0 so we know when a folder is already cached + * Values will be set by LZMA_openRead() + */ + memset(archive->files, 0, len); + + len = archive->db.Database.NumFolders * sizeof (LZMAfolder); + archive->folders = (LZMAfolder *) allocator.Malloc(len); + if (archive->folders == NULL) + { + SzArDbExFree(&archive->db, SzFreePhysicsFS); + lzma_archive_exit(archive); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } + + /* + * Init with 0 so we know when a folder is already cached + * Values will be set by LZMA_read() + */ + memset(archive->folders, 0, len); + + if(!lzma_files_init(archive)) + { + SzArDbExFree(&archive->db, SzFreePhysicsFS); + lzma_archive_exit(archive); + BAIL_MACRO(PHYSFS_ERR_OTHER_ERROR, NULL); + } + + return archive; +} /* LZMA_openArchive */ + + +/* + * Moved to seperate function so we can use alloca then immediately throw + * away the allocated stack space... + */ +static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, + const char *odir, const char *str, size_t flen) +{ + char *newstr = __PHYSFS_smallAlloc(flen + 1); + if (newstr == NULL) + return; + + memcpy(newstr, str, flen); + newstr[flen] = '\0'; + cb(callbackdata, odir, newstr); + __PHYSFS_smallFree(newstr); +} /* doEnumCallback */ + + +static void LZMA_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + size_t dlen = strlen(dname), + dlen_inc = dlen + ((dlen > 0) ? 1 : 0); + LZMAarchive *archive = (LZMAarchive *) opaque; + LZMAfile *file = NULL, + *lastFile = &archive->files[archive->db.Database.NumFiles]; + if (dlen) + { + file = lzma_find_file(archive, dname); + if (file != NULL) /* if 'file' is NULL it should stay so, otherwise errors will not be handled */ + file += 1; + } + else + { + file = archive->files; + } + + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, ); + + while (file < lastFile) + { + const char * fname = file->item->Name; + const char * dirNameEnd = fname + dlen_inc; + + if (strncmp(dname, fname, dlen) != 0) /* Stop after mismatch, archive->files is sorted */ + break; + + if (strchr(dirNameEnd, '/')) /* Skip subdirs */ + { + file++; + continue; + } + + /* Do the actual callback... */ + doEnumCallback(cb, callbackdata, origdir, dirNameEnd, strlen(dirNameEnd)); + + file++; + } +} /* LZMA_enumerateFiles */ + + +static PHYSFS_Io *LZMA_openRead(PHYSFS_Dir *opaque, const char *name, + int *fileExists) +{ + LZMAarchive *archive = (LZMAarchive *) opaque; + LZMAfile *file = lzma_find_file(archive, name); + PHYSFS_Io *io = NULL; + + *fileExists = (file != NULL); + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_NO_SUCH_PATH, NULL); + BAIL_IF_MACRO(file->folder == NULL, PHYSFS_ERR_NOT_A_FILE, NULL); + + file->position = 0; + file->folder->references++; /* Increase refcount for automatic cleanup... */ + + io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + BAIL_IF_MACRO(io == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + memcpy(io, &LZMA_Io, sizeof (*io)); + io->opaque = file; + + return io; +} /* LZMA_openRead */ + + +static PHYSFS_Io *LZMA_openWrite(PHYSFS_Dir *opaque, const char *filename) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* LZMA_openWrite */ + + +static PHYSFS_Io *LZMA_openAppend(PHYSFS_Dir *opaque, const char *filename) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* LZMA_openAppend */ + + +static void LZMA_closeArchive(PHYSFS_Dir *opaque) +{ + LZMAarchive *archive = (LZMAarchive *) opaque; + +#if 0 /* !!! FIXME: you shouldn't have to do this. */ + PHYSFS_uint32 fileIndex = 0, numFiles = archive->db.Database.NumFiles; + for (fileIndex = 0; fileIndex < numFiles; fileIndex++) + { + LZMA_fileClose(&archive->files[fileIndex]); + } /* for */ +#endif + + SzArDbExFree(&archive->db, SzFreePhysicsFS); + archive->stream.io->destroy(archive->stream.io); + lzma_archive_exit(archive); +} /* LZMA_closeArchive */ + + +static int LZMA_remove(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* LZMA_remove */ + + +static int LZMA_mkdir(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* LZMA_mkdir */ + +static int LZMA_stat(PHYSFS_Dir *opaque, const char *filename, + int *exists, PHYSFS_Stat *stat) +{ + const LZMAarchive *archive = (const LZMAarchive *) opaque; + const LZMAfile *file = lzma_find_file(archive, filename); + + *exists = (file != 0); + if (!file) + return 0; + + if(file->item->IsDirectory) + { + stat->filesize = 0; + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + } /* if */ + else + { + stat->filesize = (PHYSFS_sint64) file->item->Size; + stat->filetype = PHYSFS_FILETYPE_REGULAR; + } /* else */ + + /* !!! FIXME: the 0's should be -1's? */ + if (file->item->IsLastWriteTimeDefined) + stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime); + else + stat->modtime = 0; + + /* real create and accesstype are currently not in the lzma SDK */ + stat->createtime = stat->modtime; + stat->accesstime = 0; + + stat->readonly = 1; /* 7zips are always read only */ + + return 1; +} /* LZMA_stat */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_LZMA = +{ + { + "7Z", + "LZMA (7zip) format", + "Dennis Schridde ", + "http://icculus.org/physfs/", + }, + LZMA_openArchive, /* openArchive() method */ + LZMA_enumerateFiles, /* enumerateFiles() method */ + LZMA_openRead, /* openRead() method */ + LZMA_openWrite, /* openWrite() method */ + LZMA_openAppend, /* openAppend() method */ + LZMA_remove, /* remove() method */ + LZMA_mkdir, /* mkdir() method */ + LZMA_closeArchive, /* closeArchive() method */ + LZMA_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_7Z */ + +/* end of lzma.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_mvl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_mvl.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,103 @@ +/* + * MVL support routines for PhysicsFS. + * + * This driver handles Descent II Movielib archives. + * + * The file format of MVL is quite easy... + * + * //MVL File format - Written by Heiko Herrmann + * char sig[4] = {'D','M', 'V', 'L'}; // "DMVL"=Descent MoVie Library + * + * int num_files; // the number of files in this MVL + * + * struct { + * char file_name[13]; // Filename, padded to 13 bytes with 0s + * int file_size; // filesize in bytes + * }DIR_STRUCT[num_files]; + * + * struct { + * char data[file_size]; // The file data + * }FILE_STRUCT[num_files]; + * + * (That info is from http://www.descent2.com/ddn/specs/mvl/) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Bradley Bell. + * Based on grp.c by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_MVL + +static UNPKentry *mvlLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) +{ + PHYSFS_uint32 location = 8; /* sizeof sig. */ + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + + entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); + BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + location += (17 * fileCount); + + for (entry = entries; fileCount > 0; fileCount--, entry++) + { + if (!__PHYSFS_readAll(io, &entry->name, 13)) goto failed; + if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed; + entry->size = PHYSFS_swapULE32(entry->size); + entry->startPos = location; + location += entry->size; + } /* for */ + + return entries; + +failed: + allocator.Free(entries); + return NULL; +} /* mvlLoadEntries */ + + +static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint8 buf[4]; + PHYSFS_uint32 count = 0; + UNPKentry *entries = NULL; + + assert(io != NULL); /* shouldn't ever happen. */ + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, 4), ERRPASS, NULL); + BAIL_IF_MACRO(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL); + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof(count)), ERRPASS, NULL); + + count = PHYSFS_swapULE32(count); + entries = mvlLoadEntries(io, count); + return (!entries) ? NULL : UNPK_openArchive(io, entries, count); +} /* MVL_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_MVL = +{ + { + "MVL", + "Descent II Movielib format", + "Bradley Bell ", + "http://icculus.org/physfs/", + }, + MVL_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_MVL */ + +/* end of mvl.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_qpak.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_qpak.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,119 @@ +/* + * QPAK support routines for PhysicsFS. + * + * This archiver handles the archive format utilized by Quake 1 and 2. + * Quake3-based games use the PkZip/Info-Zip format (which our zip.c + * archiver handles). + * + * ======================================================================== + * + * This format info (in more detail) comes from: + * http://debian.fmi.uni-sofia.bg/~sergei/cgsr/docs/pak.txt + * + * Quake PAK Format + * + * Header + * (4 bytes) signature = 'PACK' + * (4 bytes) directory offset + * (4 bytes) directory length + * + * Directory + * (56 bytes) file name + * (4 bytes) file position + * (4 bytes) file length + * + * ======================================================================== + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_QPAK + +#define QPAK_SIG 0x4B434150 /* "PACK" in ASCII. */ + +static UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) +{ + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + + entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); + BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + for (entry = entries; fileCount > 0; fileCount--, entry++) + { + if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed; + if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed; + if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed; + entry->size = PHYSFS_swapULE32(entry->size); + entry->startPos = PHYSFS_swapULE32(entry->startPos); + } /* for */ + + return entries; + +failed: + allocator.Free(entries); + return NULL; +} /* qpakLoadEntries */ + + +static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + UNPKentry *entries = NULL; + PHYSFS_uint32 val = 0; + PHYSFS_uint32 pos = 0; + PHYSFS_uint32 count = 0; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); + if (PHYSFS_swapULE32(val) != QPAK_SIG) + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); + pos = PHYSFS_swapULE32(val); /* directory table offset. */ + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &val, 4), ERRPASS, NULL); + count = PHYSFS_swapULE32(val); + + /* corrupted archive? */ + BAIL_IF_MACRO((count % 64) != 0, PHYSFS_ERR_CORRUPT, NULL); + count /= 64; + + BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, NULL); + + entries = qpakLoadEntries(io, count); + BAIL_IF_MACRO(!entries, ERRPASS, NULL); + return UNPK_openArchive(io, entries, count); +} /* QPAK_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_QPAK = +{ + { + "PAK", + "Quake I/II format", + "Ryan C. Gordon ", + "http://icculus.org/physfs/", + }, + QPAK_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_QPAK */ + +/* end of qpak.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_unpacked.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_unpacked.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,470 @@ +/* + * High-level PhysicsFS archiver for simple unpacked file formats. + * + * This is a framework that basic archivers build on top of. It's for simple + * formats that can just hand back a list of files and the offsets of their + * uncompressed data. There are an alarming number of formats like this. + * + * RULES: Archive entries must be uncompressed, must not have separate subdir + * entries (but can have subdirs), must be case insensitive LOW ASCII + * filenames <= 56 bytes. No symlinks, etc. We can relax some of these rules + * as necessary. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +typedef struct +{ + PHYSFS_Io *io; + PHYSFS_uint32 entryCount; + UNPKentry *entries; +} UNPKinfo; + + +typedef struct +{ + PHYSFS_Io *io; + UNPKentry *entry; + PHYSFS_uint32 curPos; +} UNPKfileinfo; + + +void UNPK_closeArchive(PHYSFS_Dir *opaque) +{ + UNPKinfo *info = ((UNPKinfo *) opaque); + info->io->destroy(info->io); + allocator.Free(info->entries); + allocator.Free(info); +} /* UNPK_closeArchive */ + + +static PHYSFS_sint64 UNPK_read(PHYSFS_Io *io, void *buffer, PHYSFS_uint64 len) +{ + UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque; + const UNPKentry *entry = finfo->entry; + const PHYSFS_uint64 bytesLeft = (PHYSFS_uint64)(entry->size-finfo->curPos); + PHYSFS_sint64 rc; + + if (bytesLeft < len) + len = bytesLeft; + + rc = finfo->io->read(finfo->io, buffer, len); + if (rc > 0) + finfo->curPos += (PHYSFS_uint32) rc; + + return rc; +} /* UNPK_read */ + + +static PHYSFS_sint64 UNPK_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1); +} /* UNPK_write */ + + +static PHYSFS_sint64 UNPK_tell(PHYSFS_Io *io) +{ + return ((UNPKfileinfo *) io->opaque)->curPos; +} /* UNPK_tell */ + + +static int UNPK_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque; + const UNPKentry *entry = finfo->entry; + int rc; + + BAIL_IF_MACRO(offset >= entry->size, PHYSFS_ERR_PAST_EOF, 0); + rc = finfo->io->seek(finfo->io, entry->startPos + offset); + if (rc) + finfo->curPos = (PHYSFS_uint32) offset; + + return rc; +} /* UNPK_seek */ + + +static PHYSFS_sint64 UNPK_length(PHYSFS_Io *io) +{ + const UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque; + return ((PHYSFS_sint64) finfo->entry->size); +} /* UNPK_length */ + + +static PHYSFS_Io *UNPK_duplicate(PHYSFS_Io *_io) +{ + UNPKfileinfo *origfinfo = (UNPKfileinfo *) _io->opaque; + PHYSFS_Io *io = NULL; + PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + UNPKfileinfo *finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo)); + GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed); + GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_duplicate_failed); + + io = origfinfo->io->duplicate(origfinfo->io); + if (!io) goto UNPK_duplicate_failed; + finfo->io = io; + finfo->entry = origfinfo->entry; + finfo->curPos = 0; + memcpy(retval, _io, sizeof (PHYSFS_Io)); + retval->opaque = finfo; + return retval; + +UNPK_duplicate_failed: + if (finfo != NULL) allocator.Free(finfo); + if (retval != NULL) allocator.Free(retval); + if (io != NULL) io->destroy(io); + return NULL; +} /* UNPK_duplicate */ + +static int UNPK_flush(PHYSFS_Io *io) { return 1; /* no write support. */ } + +static void UNPK_destroy(PHYSFS_Io *io) +{ + UNPKfileinfo *finfo = (UNPKfileinfo *) io->opaque; + finfo->io->destroy(finfo->io); + allocator.Free(finfo); + allocator.Free(io); +} /* UNPK_destroy */ + + +static const PHYSFS_Io UNPK_Io = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + UNPK_read, + UNPK_write, + UNPK_seek, + UNPK_tell, + UNPK_length, + UNPK_duplicate, + UNPK_flush, + UNPK_destroy +}; + + +static int entryCmp(void *_a, size_t one, size_t two) +{ + if (one != two) + { + const UNPKentry *a = (const UNPKentry *) _a; + return __PHYSFS_stricmpASCII(a[one].name, a[two].name); + } /* if */ + + return 0; +} /* entryCmp */ + + +static void entrySwap(void *_a, size_t one, size_t two) +{ + if (one != two) + { + UNPKentry tmp; + UNPKentry *first = &(((UNPKentry *) _a)[one]); + UNPKentry *second = &(((UNPKentry *) _a)[two]); + memcpy(&tmp, first, sizeof (UNPKentry)); + memcpy(first, second, sizeof (UNPKentry)); + memcpy(second, &tmp, sizeof (UNPKentry)); + } /* if */ +} /* entrySwap */ + + +static PHYSFS_sint32 findStartOfDir(UNPKinfo *info, const char *path, + int stop_on_first_find) +{ + PHYSFS_sint32 lo = 0; + PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1); + PHYSFS_sint32 middle; + PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path); + PHYSFS_sint32 retval = -1; + const char *name; + int rc; + + if (*path == '\0') /* root dir? */ + return 0; + + if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */ + dlen--; + + while (lo <= hi) + { + middle = lo + ((hi - lo) / 2); + name = info->entries[middle].name; + rc = __PHYSFS_strnicmpASCII(path, name, dlen); + if (rc == 0) + { + char ch = name[dlen]; + if (ch < '/') /* make sure this isn't just a substr match. */ + rc = -1; + else if (ch > '/') + rc = 1; + else + { + if (stop_on_first_find) /* Just checking dir's existance? */ + return middle; + + if (name[dlen + 1] == '\0') /* Skip initial dir entry. */ + return (middle + 1); + + /* there might be more entries earlier in the list. */ + retval = middle; + hi = middle - 1; + } /* else */ + } /* if */ + + if (rc > 0) + lo = middle + 1; + else + hi = middle - 1; + } /* while */ + + return retval; +} /* findStartOfDir */ + + +/* + * Moved to seperate function so we can use alloca then immediately throw + * away the allocated stack space... + */ +static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, + const char *odir, const char *str, PHYSFS_sint32 ln) +{ + char *newstr = __PHYSFS_smallAlloc(ln + 1); + if (newstr == NULL) + return; + + memcpy(newstr, str, ln); + newstr[ln] = '\0'; + cb(callbackdata, odir, newstr); + __PHYSFS_smallFree(newstr); +} /* doEnumCallback */ + + +void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + UNPKinfo *info = ((UNPKinfo *) opaque); + PHYSFS_sint32 dlen, dlen_inc, max, i; + + i = findStartOfDir(info, dname, 0); + if (i == -1) /* no such directory. */ + return; + + dlen = (PHYSFS_sint32) strlen(dname); + if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */ + dlen--; + + dlen_inc = ((dlen > 0) ? 1 : 0) + dlen; + max = (PHYSFS_sint32) info->entryCount; + while (i < max) + { + char *add; + char *ptr; + PHYSFS_sint32 ln; + char *e = info->entries[i].name; + if ((dlen) && + ((__PHYSFS_strnicmpASCII(e, dname, dlen)) || (e[dlen] != '/'))) + { + break; /* past end of this dir; we're done. */ + } /* if */ + + add = e + dlen_inc; + ptr = strchr(add, '/'); + ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add)); + doEnumCallback(cb, callbackdata, origdir, add, ln); + ln += dlen_inc; /* point past entry to children... */ + + /* increment counter and skip children of subdirs... */ + while ((++i < max) && (ptr != NULL)) + { + char *e_new = info->entries[i].name; + if ((__PHYSFS_strnicmpASCII(e, e_new, ln) != 0) || + (e_new[ln] != '/')) + { + break; + } /* if */ + } /* while */ + } /* while */ +} /* UNPK_enumerateFiles */ + + +/* + * This will find the UNPKentry associated with a path in platform-independent + * notation. Directories don't have UNPKentries associated with them, but + * (*isDir) will be set to non-zero if a dir was hit. + */ +static UNPKentry *findEntry(const UNPKinfo *info, const char *path, int *isDir) +{ + UNPKentry *a = info->entries; + PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path); + PHYSFS_sint32 lo = 0; + PHYSFS_sint32 hi = (PHYSFS_sint32) (info->entryCount - 1); + PHYSFS_sint32 middle; + const char *thispath = NULL; + int rc; + + while (lo <= hi) + { + middle = lo + ((hi - lo) / 2); + thispath = a[middle].name; + rc = __PHYSFS_strnicmpASCII(path, thispath, pathlen); + + if (rc > 0) + lo = middle + 1; + + else if (rc < 0) + hi = middle - 1; + + else /* substring match...might be dir or entry or nothing. */ + { + if (isDir != NULL) + { + *isDir = (thispath[pathlen] == '/'); + if (*isDir) + return NULL; + } /* if */ + + if (thispath[pathlen] == '\0') /* found entry? */ + return &a[middle]; + /* adjust search params, try again. */ + else if (thispath[pathlen] > '/') + hi = middle - 1; + else + lo = middle + 1; + } /* if */ + } /* while */ + + if (isDir != NULL) + *isDir = 0; + + BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL); +} /* findEntry */ + + +PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists) +{ + PHYSFS_Io *retval = NULL; + UNPKinfo *info = (UNPKinfo *) opaque; + UNPKfileinfo *finfo = NULL; + int isdir = 0; + UNPKentry *entry = findEntry(info, fnm, &isdir); + + *fileExists = (entry != NULL); + GOTO_IF_MACRO(isdir, PHYSFS_ERR_NOT_A_FILE, UNPK_openRead_failed); + GOTO_IF_MACRO(!entry, ERRPASS, UNPK_openRead_failed); + + retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed); + + finfo = (UNPKfileinfo *) allocator.Malloc(sizeof (UNPKfileinfo)); + GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, UNPK_openRead_failed); + + finfo->io = info->io->duplicate(info->io); + GOTO_IF_MACRO(!finfo->io, ERRPASS, UNPK_openRead_failed); + + if (!finfo->io->seek(finfo->io, entry->startPos)) + goto UNPK_openRead_failed; + + finfo->curPos = 0; + finfo->entry = entry; + + memcpy(retval, &UNPK_Io, sizeof (*retval)); + retval->opaque = finfo; + return retval; + +UNPK_openRead_failed: + if (finfo != NULL) + { + if (finfo->io != NULL) + finfo->io->destroy(finfo->io); + allocator.Free(finfo); + } /* if */ + + if (retval != NULL) + allocator.Free(retval); + + return NULL; +} /* UNPK_openRead */ + + +PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* UNPK_openWrite */ + + +PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* UNPK_openAppend */ + + +int UNPK_remove(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* UNPK_remove */ + + +int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* UNPK_mkdir */ + + +int UNPK_stat(PHYSFS_Dir *opaque, const char *filename, + int *exists, PHYSFS_Stat *stat) +{ + int isDir = 0; + const UNPKinfo *info = (const UNPKinfo *) opaque; + const UNPKentry *entry = findEntry(info, filename, &isDir); + + if (isDir) + { + *exists = 1; + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + stat->filesize = 0; + } /* if */ + else if (entry != NULL) + { + *exists = 1; + stat->filetype = PHYSFS_FILETYPE_REGULAR; + stat->filesize = entry->size; + } /* else if */ + else + { + *exists = 0; + return 0; + } /* else */ + + stat->modtime = -1; + stat->createtime = -1; + stat->accesstime = -1; + stat->readonly = 1; + + return 1; +} /* UNPK_stat */ + + +PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io, UNPKentry *e, + const PHYSFS_uint32 num) +{ + UNPKinfo *info = (UNPKinfo *) allocator.Malloc(sizeof (UNPKinfo)); + if (info == NULL) + { + allocator.Free(e); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + __PHYSFS_sort(e, (size_t) num, entryCmp, entrySwap); + info->io = io; + info->entryCount = num; + info->entries = e; + + return info; +} /* UNPK_openArchive */ + +/* end of archiver_unpacked.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_wad.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_wad.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,127 @@ +/* + * WAD support routines for PhysicsFS. + * + * This driver handles DOOM engine archives ("wads"). + * This format (but not this driver) was designed by id Software for use + * with the DOOM engine. + * The specs of the format are from the unofficial doom specs v1.666 + * found here: http://www.gamers.org/dhs/helpdocs/dmsp1666.html + * The format of the archive: (from the specs) + * + * A WAD file has three parts: + * (1) a twelve-byte header + * (2) one or more "lumps" + * (3) a directory or "info table" that contains the names, offsets, and + * sizes of all the lumps in the WAD + * + * The header consists of three four-byte parts: + * (a) an ASCII string which must be either "IWAD" or "PWAD" + * (b) a 4-byte (long) integer which is the number of lumps in the wad + * (c) a long integer which is the file offset to the start of + * the directory + * + * The directory has one 16-byte entry for every lump. Each entry consists + * of three parts: + * + * (a) a long integer, the file offset to the start of the lump + * (b) a long integer, the size of the lump in bytes + * (c) an 8-byte ASCII string, the name of the lump, padded with zeros. + * For example, the "DEMO1" entry in hexadecimal would be + * (44 45 4D 4F 31 00 00 00) + * + * Note that there is no way to tell if an opened WAD archive is a + * IWAD or PWAD with this archiver. + * I couldn't think of a way to provide that information, without being too + * hacky. + * I don't think it's really that important though. + * + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Travis Wells, based on the GRP archiver by + * Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_WAD + +static UNPKentry *wadLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) +{ + PHYSFS_uint32 directoryOffset; + UNPKentry *entries = NULL; + UNPKentry *entry = NULL; + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &directoryOffset, 4), ERRPASS, 0); + directoryOffset = PHYSFS_swapULE32(directoryOffset); + + BAIL_IF_MACRO(!io->seek(io, directoryOffset), ERRPASS, 0); + + entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); + BAIL_IF_MACRO(!entries, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + for (entry = entries; fileCount > 0; fileCount--, entry++) + { + if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed; + if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed; + if (!__PHYSFS_readAll(io, &entry->name, 8)) goto failed; + + entry->name[8] = '\0'; /* name might not be null-terminated in file. */ + entry->size = PHYSFS_swapULE32(entry->size); + entry->startPos = PHYSFS_swapULE32(entry->startPos); + } /* for */ + + return entries; + +failed: + allocator.Free(entries); + return NULL; +} /* wadLoadEntries */ + + +static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + PHYSFS_uint8 buf[4]; + UNPKentry *entries = NULL; + PHYSFS_uint32 count = 0; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, sizeof (buf)), ERRPASS, NULL); + if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0)) + BAIL_MACRO(PHYSFS_ERR_UNSUPPORTED, NULL); + + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &count, sizeof (count)), ERRPASS, NULL); + count = PHYSFS_swapULE32(count); + + entries = wadLoadEntries(io, count); + BAIL_IF_MACRO(!entries, ERRPASS, NULL); + return UNPK_openArchive(io, entries, count); +} /* WAD_openArchive */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_WAD = +{ + { + "WAD", + "DOOM engine format", + "Travis Wells ", + "http://www.3dmm2.com/doom/", + }, + WAD_openArchive, /* openArchive() method */ + UNPK_enumerateFiles, /* enumerateFiles() method */ + UNPK_openRead, /* openRead() method */ + UNPK_openWrite, /* openWrite() method */ + UNPK_openAppend, /* openAppend() method */ + UNPK_remove, /* remove() method */ + UNPK_mkdir, /* mkdir() method */ + UNPK_closeArchive, /* closeArchive() method */ + UNPK_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_WAD */ + +/* end of wad.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/archiver_zip.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/archiver_zip.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,1717 @@ +/* + * ZIP support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon, with some peeking at "unzip.c" + * by Gilles Vollant. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#if PHYSFS_SUPPORTS_ZIP + +#include +#include + +#define USE_MINIZ 1 +#if USE_MINIZ +#include "physfs_miniz.h" +#else +#include +#endif + +/* + * A buffer of ZIP_READBUFSIZE is allocated for each compressed file opened, + * and is freed when you close the file; compressed data is read into + * this buffer, and then is decompressed into the buffer passed to + * PHYSFS_read(). + * + * Uncompressed entries in a zipfile do not allocate this buffer; they just + * read data directly into the buffer passed to PHYSFS_read(). + * + * Depending on your speed and memory requirements, you should tweak this + * value. + */ +#define ZIP_READBUFSIZE (16 * 1024) + + +/* + * Entries are "unresolved" until they are first opened. At that time, + * local file headers parsed/validated, data offsets will be updated to look + * at the actual file data instead of the header, and symlinks will be + * followed and optimized. This means that we don't seek and read around the + * archive until forced to do so, and after the first time, we had to do + * less reading and parsing, which is very CD-ROM friendly. + */ +typedef enum +{ + ZIP_UNRESOLVED_FILE, + ZIP_UNRESOLVED_SYMLINK, + ZIP_RESOLVING, + ZIP_RESOLVED, + ZIP_BROKEN_FILE, + ZIP_BROKEN_SYMLINK +} ZipResolveType; + + +/* + * One ZIPentry is kept for each file in an open ZIP archive. + */ +typedef struct _ZIPentry +{ + char *name; /* Name of file in archive */ + struct _ZIPentry *symlink; /* NULL or file we symlink to */ + ZipResolveType resolved; /* Have we resolved file/symlink? */ + PHYSFS_uint64 offset; /* offset of data in archive */ + PHYSFS_uint16 version; /* version made by */ + PHYSFS_uint16 version_needed; /* version needed to extract */ + PHYSFS_uint16 compression_method; /* compression method */ + PHYSFS_uint32 crc; /* crc-32 */ + PHYSFS_uint64 compressed_size; /* compressed size */ + PHYSFS_uint64 uncompressed_size; /* uncompressed size */ + PHYSFS_sint64 last_mod_time; /* last file mod time */ +} ZIPentry; + +/* + * One ZIPinfo is kept for each open ZIP archive. + */ +typedef struct +{ + PHYSFS_Io *io; + int zip64; /* non-zero if this is a Zip64 archive. */ + PHYSFS_uint64 entryCount; /* Number of files in ZIP. */ + ZIPentry *entries; /* info on all files in ZIP. */ +} ZIPinfo; + +/* + * One ZIPfileinfo is kept for each open file in a ZIP archive. + */ +typedef struct +{ + ZIPentry *entry; /* Info on file. */ + PHYSFS_Io *io; /* physical file handle. */ + PHYSFS_uint32 compressed_position; /* offset in compressed data. */ + PHYSFS_uint32 uncompressed_position; /* tell() position. */ + PHYSFS_uint8 *buffer; /* decompression buffer. */ + z_stream stream; /* zlib stream state. */ +} ZIPfileinfo; + + +/* Magic numbers... */ +#define ZIP_LOCAL_FILE_SIG 0x04034b50 +#define ZIP_CENTRAL_DIR_SIG 0x02014b50 +#define ZIP_END_OF_CENTRAL_DIR_SIG 0x06054b50 +#define ZIP64_END_OF_CENTRAL_DIR_SIG 0x06064b50 +#define ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG 0x07064b50 +#define ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG 0x0001 + +/* compression methods... */ +#define COMPMETH_NONE 0 +/* ...and others... */ + + +#define UNIX_FILETYPE_MASK 0170000 +#define UNIX_FILETYPE_SYMLINK 0120000 + + +/* + * Bridge physfs allocation functions to zlib's format... + */ +static voidpf zlibPhysfsAlloc(voidpf opaque, uInt items, uInt size) +{ + return ((PHYSFS_Allocator *) opaque)->Malloc(items * size); +} /* zlibPhysfsAlloc */ + +/* + * Bridge physfs allocation functions to zlib's format... + */ +static void zlibPhysfsFree(voidpf opaque, voidpf address) +{ + ((PHYSFS_Allocator *) opaque)->Free(address); +} /* zlibPhysfsFree */ + + +/* + * Construct a new z_stream to a sane state. + */ +static void initializeZStream(z_stream *pstr) +{ + memset(pstr, '\0', sizeof (z_stream)); + pstr->zalloc = zlibPhysfsAlloc; + pstr->zfree = zlibPhysfsFree; + pstr->opaque = &allocator; +} /* initializeZStream */ + + +static PHYSFS_ErrorCode zlib_error_code(int rc) +{ + switch (rc) + { + case Z_OK: return PHYSFS_ERR_OK; /* not an error. */ + case Z_STREAM_END: return PHYSFS_ERR_OK; /* not an error. */ + case Z_ERRNO: return PHYSFS_ERR_IO; + case Z_MEM_ERROR: return PHYSFS_ERR_OUT_OF_MEMORY; + default: return PHYSFS_ERR_CORRUPT; + } /* switch */ +} /* zlib_error_string */ + + +/* + * Wrap all zlib calls in this, so the physfs error state is set appropriately. + */ +static int zlib_err(const int rc) +{ + __PHYSFS_setError(zlib_error_code(rc)); + return rc; +} /* zlib_err */ + + +/* + * Read an unsigned 64-bit int and swap to native byte order. + */ +static int readui64(PHYSFS_Io *io, PHYSFS_uint64 *val) +{ + PHYSFS_uint64 v; + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0); + *val = PHYSFS_swapULE64(v); + return 1; +} /* readui64 */ + +/* + * Read an unsigned 32-bit int and swap to native byte order. + */ +static int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val) +{ + PHYSFS_uint32 v; + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0); + *val = PHYSFS_swapULE32(v); + return 1; +} /* readui32 */ + + +/* + * Read an unsigned 16-bit int and swap to native byte order. + */ +static int readui16(PHYSFS_Io *io, PHYSFS_uint16 *val) +{ + PHYSFS_uint16 v; + BAIL_IF_MACRO(!__PHYSFS_readAll(io, &v, sizeof (v)), ERRPASS, 0); + *val = PHYSFS_swapULE16(v); + return 1; +} /* readui16 */ + + +static PHYSFS_sint64 ZIP_read(PHYSFS_Io *_io, void *buf, PHYSFS_uint64 len) +{ + ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque; + PHYSFS_Io *io = finfo->io; + ZIPentry *entry = finfo->entry; + PHYSFS_sint64 retval = 0; + PHYSFS_sint64 maxread = (PHYSFS_sint64) len; + PHYSFS_sint64 avail = entry->uncompressed_size - + finfo->uncompressed_position; + + if (avail < maxread) + maxread = avail; + + BAIL_IF_MACRO(maxread == 0, ERRPASS, 0); /* quick rejection. */ + + if (entry->compression_method == COMPMETH_NONE) + retval = io->read(io, buf, maxread); + else + { + finfo->stream.next_out = buf; + finfo->stream.avail_out = (uInt) maxread; + + while (retval < maxread) + { + PHYSFS_uint32 before = finfo->stream.total_out; + int rc; + + if (finfo->stream.avail_in == 0) + { + PHYSFS_sint64 br; + + br = entry->compressed_size - finfo->compressed_position; + if (br > 0) + { + if (br > ZIP_READBUFSIZE) + br = ZIP_READBUFSIZE; + + br = io->read(io, finfo->buffer, (PHYSFS_uint64) br); + if (br <= 0) + break; + + finfo->compressed_position += (PHYSFS_uint32) br; + finfo->stream.next_in = finfo->buffer; + finfo->stream.avail_in = (PHYSFS_uint32) br; + } /* if */ + } /* if */ + + rc = zlib_err(inflate(&finfo->stream, Z_SYNC_FLUSH)); + retval += (finfo->stream.total_out - before); + + if (rc != Z_OK) + break; + } /* while */ + } /* else */ + + if (retval > 0) + finfo->uncompressed_position += (PHYSFS_uint32) retval; + + return retval; +} /* ZIP_read */ + + +static PHYSFS_sint64 ZIP_write(PHYSFS_Io *io, const void *b, PHYSFS_uint64 len) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, -1); +} /* ZIP_write */ + + +static PHYSFS_sint64 ZIP_tell(PHYSFS_Io *io) +{ + return ((ZIPfileinfo *) io->opaque)->uncompressed_position; +} /* ZIP_tell */ + + +static int ZIP_seek(PHYSFS_Io *_io, PHYSFS_uint64 offset) +{ + ZIPfileinfo *finfo = (ZIPfileinfo *) _io->opaque; + ZIPentry *entry = finfo->entry; + PHYSFS_Io *io = finfo->io; + + BAIL_IF_MACRO(offset > entry->uncompressed_size, PHYSFS_ERR_PAST_EOF, 0); + + if (entry->compression_method == COMPMETH_NONE) + { + const PHYSFS_sint64 newpos = offset + entry->offset; + BAIL_IF_MACRO(!io->seek(io, newpos), ERRPASS, 0); + finfo->uncompressed_position = (PHYSFS_uint32) offset; + } /* if */ + + else + { + /* + * If seeking backwards, we need to redecode the file + * from the start and throw away the compressed bits until we hit + * the offset we need. If seeking forward, we still need to + * decode, but we don't rewind first. + */ + if (offset < finfo->uncompressed_position) + { + /* we do a copy so state is sane if inflateInit2() fails. */ + z_stream str; + initializeZStream(&str); + if (zlib_err(inflateInit2(&str, -MAX_WBITS)) != Z_OK) + return 0; + + if (!io->seek(io, entry->offset)) + return 0; + + inflateEnd(&finfo->stream); + memcpy(&finfo->stream, &str, sizeof (z_stream)); + finfo->uncompressed_position = finfo->compressed_position = 0; + } /* if */ + + while (finfo->uncompressed_position != offset) + { + PHYSFS_uint8 buf[512]; + PHYSFS_uint32 maxread; + + maxread = (PHYSFS_uint32) (offset - finfo->uncompressed_position); + if (maxread > sizeof (buf)) + maxread = sizeof (buf); + + if (ZIP_read(_io, buf, maxread) != maxread) + return 0; + } /* while */ + } /* else */ + + return 1; +} /* ZIP_seek */ + + +static PHYSFS_sint64 ZIP_length(PHYSFS_Io *io) +{ + const ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque; + return (PHYSFS_sint64) finfo->entry->uncompressed_size; +} /* ZIP_length */ + + +static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry); + +static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io) +{ + ZIPfileinfo *origfinfo = (ZIPfileinfo *) io->opaque; + PHYSFS_Io *retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + ZIPfileinfo *finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo)); + GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, failed); + GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, failed); + memset(finfo, '\0', sizeof (*finfo)); + + finfo->entry = origfinfo->entry; + finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry); + GOTO_IF_MACRO(!finfo->io, ERRPASS, failed); + + if (finfo->entry->compression_method != COMPMETH_NONE) + { + finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE); + GOTO_IF_MACRO(!finfo->buffer, PHYSFS_ERR_OUT_OF_MEMORY, failed); + if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK) + goto failed; + } /* if */ + + memcpy(retval, io, sizeof (PHYSFS_Io)); + retval->opaque = finfo; + return retval; + +failed: + if (finfo != NULL) + { + if (finfo->io != NULL) + finfo->io->destroy(finfo->io); + + if (finfo->buffer != NULL) + { + allocator.Free(finfo->buffer); + inflateEnd(&finfo->stream); + } /* if */ + + allocator.Free(finfo); + } /* if */ + + if (retval != NULL) + allocator.Free(retval); + + return NULL; +} /* ZIP_duplicate */ + +static int ZIP_flush(PHYSFS_Io *io) { return 1; /* no write support. */ } + +static void ZIP_destroy(PHYSFS_Io *io) +{ + ZIPfileinfo *finfo = (ZIPfileinfo *) io->opaque; + finfo->io->destroy(finfo->io); + + if (finfo->entry->compression_method != COMPMETH_NONE) + inflateEnd(&finfo->stream); + + if (finfo->buffer != NULL) + allocator.Free(finfo->buffer); + + allocator.Free(finfo); + allocator.Free(io); +} /* ZIP_destroy */ + + +static const PHYSFS_Io ZIP_Io = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + ZIP_read, + ZIP_write, + ZIP_seek, + ZIP_tell, + ZIP_length, + ZIP_duplicate, + ZIP_flush, + ZIP_destroy +}; + + + +static PHYSFS_sint64 zip_find_end_of_central_dir(PHYSFS_Io *io, PHYSFS_sint64 *len) +{ + PHYSFS_uint8 buf[256]; + PHYSFS_uint8 extra[4] = { 0, 0, 0, 0 }; + PHYSFS_sint32 i = 0; + PHYSFS_sint64 filelen; + PHYSFS_sint64 filepos; + PHYSFS_sint32 maxread; + PHYSFS_sint32 totalread = 0; + int found = 0; + + filelen = io->length(io); + BAIL_IF_MACRO(filelen == -1, ERRPASS, 0); + + /* + * Jump to the end of the file and start reading backwards. + * The last thing in the file is the zipfile comment, which is variable + * length, and the field that specifies its size is before it in the + * file (argh!)...this means that we need to scan backwards until we + * hit the end-of-central-dir signature. We can then sanity check that + * the comment was as big as it should be to make sure we're in the + * right place. The comment length field is 16 bits, so we can stop + * searching for that signature after a little more than 64k at most, + * and call it a corrupted zipfile. + */ + + if (sizeof (buf) < filelen) + { + filepos = filelen - sizeof (buf); + maxread = sizeof (buf); + } /* if */ + else + { + filepos = 0; + maxread = (PHYSFS_uint32) filelen; + } /* else */ + + while ((totalread < filelen) && (totalread < 65557)) + { + BAIL_IF_MACRO(!io->seek(io, filepos), ERRPASS, -1); + + /* make sure we catch a signature between buffers. */ + if (totalread != 0) + { + if (!__PHYSFS_readAll(io, buf, maxread - 4)) + return -1; + memcpy(&buf[maxread - 4], &extra, sizeof (extra)); + totalread += maxread - 4; + } /* if */ + else + { + if (!__PHYSFS_readAll(io, buf, maxread)) + return -1; + totalread += maxread; + } /* else */ + + memcpy(&extra, buf, sizeof (extra)); + + for (i = maxread - 4; i > 0; i--) + { + if ((buf[i + 0] == 0x50) && + (buf[i + 1] == 0x4B) && + (buf[i + 2] == 0x05) && + (buf[i + 3] == 0x06) ) + { + found = 1; /* that's the signature! */ + break; + } /* if */ + } /* for */ + + if (found) + break; + + filepos -= (maxread - 4); + if (filepos < 0) + filepos = 0; + } /* while */ + + BAIL_IF_MACRO(!found, PHYSFS_ERR_UNSUPPORTED, -1); + + if (len != NULL) + *len = filelen; + + return (filepos + i); +} /* zip_find_end_of_central_dir */ + + +static int isZip(PHYSFS_Io *io) +{ + PHYSFS_uint32 sig = 0; + int retval = 0; + + /* + * The first thing in a zip file might be the signature of the + * first local file record, so it makes for a quick determination. + */ + if (readui32(io, &sig)) + { + retval = (sig == ZIP_LOCAL_FILE_SIG); + if (!retval) + { + /* + * No sig...might be a ZIP with data at the start + * (a self-extracting executable, etc), so we'll have to do + * it the hard way... + */ + retval = (zip_find_end_of_central_dir(io, NULL) != -1); + } /* if */ + } /* if */ + + return retval; +} /* isZip */ + + +static void zip_free_entries(ZIPentry *entries, PHYSFS_uint64 max) +{ + PHYSFS_uint64 i; + for (i = 0; i < max; i++) + { + ZIPentry *entry = &entries[i]; + if (entry->name != NULL) + allocator.Free(entry->name); + } /* for */ + + allocator.Free(entries); +} /* zip_free_entries */ + + +/* + * This will find the ZIPentry associated with a path in platform-independent + * notation. Directories don't have ZIPentries associated with them, but + * (*isDir) will be set to non-zero if a dir was hit. + */ +static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path, + int *isDir) +{ + ZIPentry *a = info->entries; + PHYSFS_sint32 pathlen = (PHYSFS_sint32) strlen(path); + PHYSFS_sint64 lo = 0; + PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1); + PHYSFS_sint64 middle; + const char *thispath = NULL; + int rc; + + while (lo <= hi) + { + middle = lo + ((hi - lo) / 2); + thispath = a[middle].name; + rc = strncmp(path, thispath, pathlen); + + if (rc > 0) + lo = middle + 1; + + else if (rc < 0) + hi = middle - 1; + + else /* substring match...might be dir or entry or nothing. */ + { + if (isDir != NULL) + { + *isDir = (thispath[pathlen] == '/'); + if (*isDir) + return NULL; + } /* if */ + + if (thispath[pathlen] == '\0') /* found entry? */ + return &a[middle]; + /* adjust search params, try again. */ + else if (thispath[pathlen] > '/') + hi = middle - 1; + else + lo = middle + 1; + } /* if */ + } /* while */ + + if (isDir != NULL) + *isDir = 0; + + BAIL_MACRO(PHYSFS_ERR_NO_SUCH_PATH, NULL); +} /* zip_find_entry */ + + +/* Convert paths from old, buggy DOS zippers... */ +static void zip_convert_dos_path(ZIPentry *entry, char *path) +{ + PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((entry->version >> 8) & 0xFF); + if (hosttype == 0) /* FS_FAT_ */ + { + while (*path) + { + if (*path == '\\') + *path = '/'; + path++; + } /* while */ + } /* if */ +} /* zip_convert_dos_path */ + + +static void zip_expand_symlink_path(char *path) +{ + char *ptr = path; + char *prevptr = path; + + while (1) + { + ptr = strchr(ptr, '/'); + if (ptr == NULL) + break; + + if (*(ptr + 1) == '.') + { + if (*(ptr + 2) == '/') + { + /* current dir in middle of string: ditch it. */ + memmove(ptr, ptr + 2, strlen(ptr + 2) + 1); + } /* else if */ + + else if (*(ptr + 2) == '\0') + { + /* current dir at end of string: ditch it. */ + *ptr = '\0'; + } /* else if */ + + else if (*(ptr + 2) == '.') + { + if (*(ptr + 3) == '/') + { + /* parent dir in middle: move back one, if possible. */ + memmove(prevptr, ptr + 4, strlen(ptr + 4) + 1); + ptr = prevptr; + while (prevptr != path) + { + prevptr--; + if (*prevptr == '/') + { + prevptr++; + break; + } /* if */ + } /* while */ + } /* if */ + + if (*(ptr + 3) == '\0') + { + /* parent dir at end: move back one, if possible. */ + *prevptr = '\0'; + } /* if */ + } /* if */ + } /* if */ + else + { + prevptr = ptr; + ptr++; + } /* else */ + } /* while */ +} /* zip_expand_symlink_path */ + +/* (forward reference: zip_follow_symlink and zip_resolve call each other.) */ +static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry); + +/* + * Look for the entry named by (path). If it exists, resolve it, and return + * a pointer to that entry. If it's another symlink, keep resolving until you + * hit a real file and then return a pointer to the final non-symlink entry. + * If there's a problem, return NULL. + */ +static ZIPentry *zip_follow_symlink(PHYSFS_Io *io, ZIPinfo *info, char *path) +{ + ZIPentry *entry; + + zip_expand_symlink_path(path); + entry = zip_find_entry(info, path, NULL); + if (entry != NULL) + { + if (!zip_resolve(io, info, entry)) /* recursive! */ + entry = NULL; + else + { + if (entry->symlink != NULL) + entry = entry->symlink; + } /* else */ + } /* if */ + + return entry; +} /* zip_follow_symlink */ + + +static int zip_resolve_symlink(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry) +{ + const PHYSFS_uint64 size = entry->uncompressed_size; + char *path = NULL; + int rc = 0; + + /* + * We've already parsed the local file header of the symlink at this + * point. Now we need to read the actual link from the file data and + * follow it. + */ + + BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0); + + path = (char *) __PHYSFS_smallAlloc(size + 1); + BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + if (entry->compression_method == COMPMETH_NONE) + rc = __PHYSFS_readAll(io, path, size); + + else /* symlink target path is compressed... */ + { + z_stream stream; + const PHYSFS_uint64 complen = entry->compressed_size; + PHYSFS_uint8 *compressed = (PHYSFS_uint8*) __PHYSFS_smallAlloc(complen); + if (compressed != NULL) + { + if (__PHYSFS_readAll(io, compressed, complen)) + { + initializeZStream(&stream); + stream.next_in = compressed; + stream.avail_in = complen; + stream.next_out = (unsigned char *) path; + stream.avail_out = size; + if (zlib_err(inflateInit2(&stream, -MAX_WBITS)) == Z_OK) + { + rc = zlib_err(inflate(&stream, Z_FINISH)); + inflateEnd(&stream); + + /* both are acceptable outcomes... */ + rc = ((rc == Z_OK) || (rc == Z_STREAM_END)); + } /* if */ + } /* if */ + __PHYSFS_smallFree(compressed); + } /* if */ + } /* else */ + + if (rc) + { + path[entry->uncompressed_size] = '\0'; /* null-terminate it. */ + zip_convert_dos_path(entry, path); + entry->symlink = zip_follow_symlink(io, info, path); + } /* else */ + + __PHYSFS_smallFree(path); + + return (entry->symlink != NULL); +} /* zip_resolve_symlink */ + + +/* + * Parse the local file header of an entry, and update entry->offset. + */ +static int zip_parse_local(PHYSFS_Io *io, ZIPentry *entry) +{ + PHYSFS_uint32 ui32; + PHYSFS_uint16 ui16; + PHYSFS_uint16 fnamelen; + PHYSFS_uint16 extralen; + + /* + * crc and (un)compressed_size are always zero if this is a "JAR" + * archive created with Sun's Java tools, apparently. We only + * consider this archive corrupted if those entries don't match and + * aren't zero. That seems to work well. + * We also ignore a mismatch if the value is 0xFFFFFFFF here, since it's + * possible that's a Zip64 thing. + */ + + BAIL_IF_MACRO(!io->seek(io, entry->offset), ERRPASS, 0); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != ZIP_LOCAL_FILE_SIG, PHYSFS_ERR_CORRUPT, 0); + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + BAIL_IF_MACRO(ui16 != entry->version_needed, PHYSFS_ERR_CORRUPT, 0); + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits. */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + BAIL_IF_MACRO(ui16 != entry->compression_method, PHYSFS_ERR_CORRUPT, 0); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); /* date/time */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 && (ui32 != entry->crc), PHYSFS_ERR_CORRUPT, 0); + + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) && + (ui32 != entry->compressed_size), PHYSFS_ERR_CORRUPT, 0); + + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 && (ui32 != 0xFFFFFFFF) && + (ui32 != entry->uncompressed_size), PHYSFS_ERR_CORRUPT, 0); + + BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0); + + entry->offset += fnamelen + extralen + 30; + return 1; +} /* zip_parse_local */ + + +static int zip_resolve(PHYSFS_Io *io, ZIPinfo *info, ZIPentry *entry) +{ + int retval = 1; + ZipResolveType resolve_type = entry->resolved; + + /* Don't bother if we've failed to resolve this entry before. */ + BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_FILE, PHYSFS_ERR_CORRUPT, 0); + BAIL_IF_MACRO(resolve_type == ZIP_BROKEN_SYMLINK, PHYSFS_ERR_CORRUPT, 0); + + /* uhoh...infinite symlink loop! */ + BAIL_IF_MACRO(resolve_type == ZIP_RESOLVING, PHYSFS_ERR_SYMLINK_LOOP, 0); + + /* + * We fix up the offset to point to the actual data on the + * first open, since we don't want to seek across the whole file on + * archive open (can be SLOW on large, CD-stored files), but we + * need to check the local file header...not just for corruption, + * but since it stores offset info the central directory does not. + */ + if (resolve_type != ZIP_RESOLVED) + { + entry->resolved = ZIP_RESOLVING; + + retval = zip_parse_local(io, entry); + if (retval) + { + /* + * If it's a symlink, find the original file. This will cause + * resolution of other entries (other symlinks and, eventually, + * the real file) if all goes well. + */ + if (resolve_type == ZIP_UNRESOLVED_SYMLINK) + retval = zip_resolve_symlink(io, info, entry); + } /* if */ + + if (resolve_type == ZIP_UNRESOLVED_SYMLINK) + entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_SYMLINK); + else if (resolve_type == ZIP_UNRESOLVED_FILE) + entry->resolved = ((retval) ? ZIP_RESOLVED : ZIP_BROKEN_FILE); + } /* if */ + + return retval; +} /* zip_resolve */ + + +static int zip_version_does_symlinks(PHYSFS_uint32 version) +{ + int retval = 0; + PHYSFS_uint8 hosttype = (PHYSFS_uint8) ((version >> 8) & 0xFF); + + switch (hosttype) + { + /* + * These are the platforms that can NOT build an archive with + * symlinks, according to the Info-ZIP project. + */ + case 0: /* FS_FAT_ */ + case 1: /* AMIGA_ */ + case 2: /* VMS_ */ + case 4: /* VM_CSM_ */ + case 6: /* FS_HPFS_ */ + case 11: /* FS_NTFS_ */ + case 14: /* FS_VFAT_ */ + case 13: /* ACORN_ */ + case 15: /* MVS_ */ + case 18: /* THEOS_ */ + break; /* do nothing. */ + + default: /* assume the rest to be unix-like. */ + retval = 1; + break; + } /* switch */ + + return retval; +} /* zip_version_does_symlinks */ + + +static int zip_entry_is_symlink(const ZIPentry *entry) +{ + return ((entry->resolved == ZIP_UNRESOLVED_SYMLINK) || + (entry->resolved == ZIP_BROKEN_SYMLINK) || + (entry->symlink)); +} /* zip_entry_is_symlink */ + + +static int zip_has_symlink_attr(ZIPentry *entry, PHYSFS_uint32 extern_attr) +{ + PHYSFS_uint16 xattr = ((extern_attr >> 16) & 0xFFFF); + return ( (zip_version_does_symlinks(entry->version)) && + (entry->uncompressed_size > 0) && + ((xattr & UNIX_FILETYPE_MASK) == UNIX_FILETYPE_SYMLINK) ); +} /* zip_has_symlink_attr */ + + +static PHYSFS_sint64 zip_dos_time_to_physfs_time(PHYSFS_uint32 dostime) +{ + PHYSFS_uint32 dosdate; + struct tm unixtime; + memset(&unixtime, '\0', sizeof (unixtime)); + + dosdate = (PHYSFS_uint32) ((dostime >> 16) & 0xFFFF); + dostime &= 0xFFFF; + + /* dissect date */ + unixtime.tm_year = ((dosdate >> 9) & 0x7F) + 80; + unixtime.tm_mon = ((dosdate >> 5) & 0x0F) - 1; + unixtime.tm_mday = ((dosdate ) & 0x1F); + + /* dissect time */ + unixtime.tm_hour = ((dostime >> 11) & 0x1F); + unixtime.tm_min = ((dostime >> 5) & 0x3F); + unixtime.tm_sec = ((dostime << 1) & 0x3E); + + /* let mktime calculate daylight savings time. */ + unixtime.tm_isdst = -1; + + return ((PHYSFS_sint64) mktime(&unixtime)); +} /* zip_dos_time_to_physfs_time */ + + +static int zip_load_entry(PHYSFS_Io *io, const int zip64, ZIPentry *entry, + PHYSFS_uint64 ofs_fixup) +{ + PHYSFS_uint16 fnamelen, extralen, commentlen; + PHYSFS_uint32 external_attr; + PHYSFS_uint32 starting_disk; + PHYSFS_uint64 offset; + PHYSFS_uint16 ui16; + PHYSFS_uint32 ui32; + PHYSFS_sint64 si64; + + /* sanity check with central directory signature... */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != ZIP_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0); + + /* Get the pertinent parts of the record... */ + BAIL_IF_MACRO(!readui16(io, &entry->version), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &entry->version_needed), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* general bits */ + BAIL_IF_MACRO(!readui16(io, &entry->compression_method), ERRPASS, 0); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + entry->last_mod_time = zip_dos_time_to_physfs_time(ui32); + BAIL_IF_MACRO(!readui32(io, &entry->crc), ERRPASS, 0); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + entry->compressed_size = (PHYSFS_uint64) ui32; + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + entry->uncompressed_size = (PHYSFS_uint64) ui32; + BAIL_IF_MACRO(!readui16(io, &fnamelen), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &extralen), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &commentlen), ERRPASS, 0); + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + starting_disk = (PHYSFS_uint32) ui16; + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); /* internal file attribs */ + BAIL_IF_MACRO(!readui32(io, &external_attr), ERRPASS, 0); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + offset = (PHYSFS_uint64) ui32; + + entry->symlink = NULL; /* will be resolved later, if necessary. */ + entry->resolved = (zip_has_symlink_attr(entry, external_attr)) ? + ZIP_UNRESOLVED_SYMLINK : ZIP_UNRESOLVED_FILE; + + entry->name = (char *) allocator.Malloc(fnamelen + 1); + BAIL_IF_MACRO(entry->name == NULL, PHYSFS_ERR_OUT_OF_MEMORY, 0); + if (!__PHYSFS_readAll(io, entry->name, fnamelen)) + goto zip_load_entry_puked; + + entry->name[fnamelen] = '\0'; /* null-terminate the filename. */ + zip_convert_dos_path(entry, entry->name); + + si64 = io->tell(io); + if (si64 == -1) + goto zip_load_entry_puked; + + /* + * The actual sizes didn't fit in 32-bits; look for the Zip64 + * extended information extra field... + */ + if ( (zip64) && + ((offset == 0xFFFFFFFF) || + (starting_disk == 0xFFFFFFFF) || + (entry->compressed_size == 0xFFFFFFFF) || + (entry->uncompressed_size == 0xFFFFFFFF)) ) + { + int found = 0; + PHYSFS_uint16 sig, len; + while (extralen > 4) + { + if (!readui16(io, &sig)) + goto zip_load_entry_puked; + else if (!readui16(io, &len)) + goto zip_load_entry_puked; + + si64 += 4 + len; + extralen -= 4 + len; + if (sig != ZIP64_EXTENDED_INFO_EXTRA_FIELD_SIG) + { + if (!io->seek(io, si64)) + goto zip_load_entry_puked; + continue; + } /* if */ + + found = 1; + break; + } /* while */ + + GOTO_IF_MACRO(!found, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + + if (entry->uncompressed_size == 0xFFFFFFFF) + { + GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + if (!readui64(io, &entry->uncompressed_size)) + goto zip_load_entry_puked; + len -= 8; + } /* if */ + + if (entry->compressed_size == 0xFFFFFFFF) + { + GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + if (!readui64(io, &entry->compressed_size)) + goto zip_load_entry_puked; + len -= 8; + } /* if */ + + if (offset == 0xFFFFFFFF) + { + GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + if (!readui64(io, &offset)) + goto zip_load_entry_puked; + len -= 8; + } /* if */ + + if (starting_disk == 0xFFFFFFFF) + { + GOTO_IF_MACRO(len < 8, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + if (!readui32(io, &starting_disk)) + goto zip_load_entry_puked; + len -= 4; + } /* if */ + + GOTO_IF_MACRO(len != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + } /* if */ + + GOTO_IF_MACRO(starting_disk != 0, PHYSFS_ERR_CORRUPT, zip_load_entry_puked); + + entry->offset = offset + ofs_fixup; + + /* seek to the start of the next entry in the central directory... */ + if (!io->seek(io, si64 + extralen + commentlen)) + goto zip_load_entry_puked; + + return 1; /* success. */ + +zip_load_entry_puked: + allocator.Free(entry->name); + return 0; /* failure. */ +} /* zip_load_entry */ + + +static int zip_entry_cmp(void *_a, size_t one, size_t two) +{ + if (one != two) + { + const ZIPentry *a = (const ZIPentry *) _a; + return strcmp(a[one].name, a[two].name); + } /* if */ + + return 0; +} /* zip_entry_cmp */ + + +static void zip_entry_swap(void *_a, size_t one, size_t two) +{ + if (one != two) + { + ZIPentry tmp; + ZIPentry *first = &(((ZIPentry *) _a)[one]); + ZIPentry *second = &(((ZIPentry *) _a)[two]); + memcpy(&tmp, first, sizeof (ZIPentry)); + memcpy(first, second, sizeof (ZIPentry)); + memcpy(second, &tmp, sizeof (ZIPentry)); + } /* if */ +} /* zip_entry_swap */ + + +static int zip_load_entries(PHYSFS_Io *io, ZIPinfo *info, + const PHYSFS_uint64 data_ofs, + const PHYSFS_uint64 central_ofs) +{ + const PHYSFS_uint64 max = info->entryCount; + const int zip64 = info->zip64; + PHYSFS_uint64 i; + + BAIL_IF_MACRO(!io->seek(io, central_ofs), ERRPASS, 0); + + info->entries = (ZIPentry *) allocator.Malloc(sizeof (ZIPentry) * max); + BAIL_IF_MACRO(!info->entries, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + for (i = 0; i < max; i++) + { + if (!zip_load_entry(io, zip64, &info->entries[i], data_ofs)) + { + zip_free_entries(info->entries, i); + return 0; + } /* if */ + } /* for */ + + __PHYSFS_sort(info->entries, (size_t) max, zip_entry_cmp, zip_entry_swap); + return 1; +} /* zip_load_entries */ + + +static PHYSFS_sint64 zip64_find_end_of_central_dir(PHYSFS_Io *io, + PHYSFS_sint64 _pos, + PHYSFS_uint64 offset) +{ + /* + * Naturally, the offset is useless to us; it is the offset from the + * start of file, which is meaningless if we've appended this .zip to + * a self-extracting .exe. We need to find this on our own. It should + * be directly before the locator record, but the record in question, + * like the original end-of-central-directory record, ends with a + * variable-length field. Unlike the original, which has to store the + * size of that variable-length field in a 16-bit int and thus has to be + * within 64k, the new one gets 64-bits. + * + * Fortunately, the only currently-specified record for that variable + * length block is some weird proprietary thing that deals with EBCDIC + * and tape backups or something. So we don't seek far. + */ + + PHYSFS_uint32 ui32; + const PHYSFS_uint64 pos = (PHYSFS_uint64) _pos; + + assert(_pos > 0); + + /* Try offset specified in the Zip64 end of central directory locator. */ + /* This works if the entire PHYSFS_Io is the zip file. */ + BAIL_IF_MACRO(!io->seek(io, offset), ERRPASS, -1); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1); + if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG) + return offset; + + /* Try 56 bytes before the Zip64 end of central directory locator. */ + /* This works if the record isn't variable length and is version 1. */ + if (pos > 56) + { + BAIL_IF_MACRO(!io->seek(io, pos-56), ERRPASS, -1); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1); + if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG) + return pos-56; + } /* if */ + + /* Try 84 bytes before the Zip64 end of central directory locator. */ + /* This works if the record isn't variable length and is version 2. */ + if (pos > 84) + { + BAIL_IF_MACRO(!io->seek(io, pos-84), ERRPASS, -1); + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, -1); + if (ui32 == ZIP64_END_OF_CENTRAL_DIR_SIG) + return pos-84; + } /* if */ + + /* Ok, brute force: we know it's between (offset) and (pos) somewhere. */ + /* Just try moving back at most 256k. Oh well. */ + if ((offset < pos) && (pos > 4)) + { + /* we assume you can eat this stack if you handle Zip64 files. */ + PHYSFS_uint8 buf[256 * 1024]; + PHYSFS_uint64 len = pos - offset; + PHYSFS_sint32 i; + + if (len > sizeof (buf)) + len = sizeof (buf); + + BAIL_IF_MACRO(!io->seek(io, pos - len), ERRPASS, -1); + BAIL_IF_MACRO(!__PHYSFS_readAll(io, buf, len), ERRPASS, -1); + for (i = (PHYSFS_sint32) (len - 4); i >= 0; i--) + { + if (buf[i] != 0x50) + continue; + if ( (buf[i+1] == 0x4b) && + (buf[i+2] == 0x06) && + (buf[i+3] == 0x06) ) + return pos - (len - i); + } /* for */ + } /* if */ + + BAIL_MACRO(PHYSFS_ERR_CORRUPT, -1); /* didn't find it. */ +} /* zip64_find_end_of_central_dir */ + + +static int zip64_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info, + PHYSFS_uint64 *data_start, + PHYSFS_uint64 *dir_ofs, + PHYSFS_sint64 pos) +{ + PHYSFS_uint64 ui64; + PHYSFS_uint32 ui32; + PHYSFS_uint16 ui16; + + /* We should be positioned right past the locator signature. */ + + if ((pos < 0) || (!io->seek(io, pos))) + return 0; + + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + if (ui32 != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG) + return -1; /* it's not a Zip64 archive. Not an error, though! */ + + info->zip64 = 1; + + /* number of the disk with the start of the central directory. */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0); + + /* offset of Zip64 end of central directory record. */ + BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0); + + /* total number of disks */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != 1, PHYSFS_ERR_CORRUPT, 0); + + pos = zip64_find_end_of_central_dir(io, pos, ui64); + if (pos < 0) + return 0; /* oh well. */ + + /* + * For self-extracting archives, etc, there's crapola in the file + * before the zipfile records; we calculate how much data there is + * prepended by determining how far the zip64-end-of-central-directory + * offset is from where it is supposed to be...the difference in bytes + * is how much arbitrary data is at the start of the physical file. + */ + assert(((PHYSFS_uint64) pos) >= ui64); + *data_start = ((PHYSFS_uint64) pos) - ui64; + + BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0); + + /* check signature again, just in case. */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != ZIP64_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0); + + /* size of Zip64 end of central directory record. */ + BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0); + + /* version made by. */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + + /* version needed to extract. */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + + /* number of this disk. */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0); + + /* number of disk with start of central directory record. */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != 0, PHYSFS_ERR_CORRUPT, 0); + + /* total number of entries in the central dir on this disk */ + BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0); + + /* total number of entries in the central dir */ + BAIL_IF_MACRO(!readui64(io, &info->entryCount), ERRPASS, 0); + BAIL_IF_MACRO(ui64 != info->entryCount, PHYSFS_ERR_CORRUPT, 0); + + /* size of the central directory */ + BAIL_IF_MACRO(!readui64(io, &ui64), ERRPASS, 0); + + /* offset of central directory */ + BAIL_IF_MACRO(!readui64(io, dir_ofs), ERRPASS, 0); + + /* Since we know the difference, fix up the central dir offset... */ + *dir_ofs += *data_start; + + /* + * There are more fields here, for encryption and feature-specific things, + * but we don't care about any of them at the moment. + */ + + return 1; /* made it. */ +} /* zip64_parse_end_of_central_dir */ + + +static int zip_parse_end_of_central_dir(PHYSFS_Io *io, ZIPinfo *info, + PHYSFS_uint64 *data_start, + PHYSFS_uint64 *dir_ofs) +{ + PHYSFS_uint16 entryCount16; + PHYSFS_uint32 offset32; + PHYSFS_uint32 ui32; + PHYSFS_uint16 ui16; + PHYSFS_sint64 len; + PHYSFS_sint64 pos; + int rc; + + /* find the end-of-central-dir record, and seek to it. */ + pos = zip_find_end_of_central_dir(io, &len); + BAIL_IF_MACRO(pos == -1, ERRPASS, 0); + BAIL_IF_MACRO(!io->seek(io, pos), ERRPASS, 0); + + /* check signature again, just in case. */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + BAIL_IF_MACRO(ui32 != ZIP_END_OF_CENTRAL_DIR_SIG, PHYSFS_ERR_CORRUPT, 0); + + /* Seek back to see if "Zip64 end of central directory locator" exists. */ + /* this record is 20 bytes before end-of-central-dir */ + rc = zip64_parse_end_of_central_dir(io, info, data_start, dir_ofs, pos-20); + BAIL_IF_MACRO(rc == 0, ERRPASS, 0); + if (rc == 1) + return 1; /* we're done here. */ + + assert(rc == -1); /* no error, just not a Zip64 archive. */ + + /* Not Zip64? Seek back to where we were and keep processing. */ + BAIL_IF_MACRO(!io->seek(io, pos + 4), ERRPASS, 0); + + /* number of this disk */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0); + + /* number of the disk with the start of the central directory */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + BAIL_IF_MACRO(ui16 != 0, PHYSFS_ERR_CORRUPT, 0); + + /* total number of entries in the central dir on this disk */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + + /* total number of entries in the central dir */ + BAIL_IF_MACRO(!readui16(io, &entryCount16), ERRPASS, 0); + BAIL_IF_MACRO(ui16 != entryCount16, PHYSFS_ERR_CORRUPT, 0); + + info->entryCount = entryCount16; + + /* size of the central directory */ + BAIL_IF_MACRO(!readui32(io, &ui32), ERRPASS, 0); + + /* offset of central directory */ + BAIL_IF_MACRO(!readui32(io, &offset32), ERRPASS, 0); + *dir_ofs = (PHYSFS_uint64) offset32; + BAIL_IF_MACRO(pos < (*dir_ofs + ui32), PHYSFS_ERR_CORRUPT, 0); + + /* + * For self-extracting archives, etc, there's crapola in the file + * before the zipfile records; we calculate how much data there is + * prepended by determining how far the central directory offset is + * from where it is supposed to be (start of end-of-central-dir minus + * sizeof central dir)...the difference in bytes is how much arbitrary + * data is at the start of the physical file. + */ + *data_start = (PHYSFS_uint64) (pos - (*dir_ofs + ui32)); + + /* Now that we know the difference, fix up the central dir offset... */ + *dir_ofs += *data_start; + + /* zipfile comment length */ + BAIL_IF_MACRO(!readui16(io, &ui16), ERRPASS, 0); + + /* + * Make sure that the comment length matches to the end of file... + * If it doesn't, we're either in the wrong part of the file, or the + * file is corrupted, but we give up either way. + */ + BAIL_IF_MACRO((pos + 22 + ui16) != len, PHYSFS_ERR_CORRUPT, 0); + + return 1; /* made it. */ +} /* zip_parse_end_of_central_dir */ + + +static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting) +{ + ZIPinfo *info = NULL; + PHYSFS_uint64 data_start; + PHYSFS_uint64 cent_dir_ofs; + + assert(io != NULL); /* shouldn't ever happen. */ + + BAIL_IF_MACRO(forWriting, PHYSFS_ERR_READ_ONLY, NULL); + BAIL_IF_MACRO(!isZip(io), ERRPASS, NULL); + + info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo)); + BAIL_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + memset(info, '\0', sizeof (ZIPinfo)); + info->io = io; + + if (!zip_parse_end_of_central_dir(io, info, &data_start, ¢_dir_ofs)) + goto ZIP_openarchive_failed; + + if (!zip_load_entries(io, info, data_start, cent_dir_ofs)) + goto ZIP_openarchive_failed; + + return info; + +ZIP_openarchive_failed: + if (info != NULL) + allocator.Free(info); + + return NULL; +} /* ZIP_openArchive */ + + +static PHYSFS_sint64 zip_find_start_of_dir(ZIPinfo *info, const char *path, + int stop_on_first_find) +{ + PHYSFS_sint64 lo = 0; + PHYSFS_sint64 hi = (PHYSFS_sint64) (info->entryCount - 1); + PHYSFS_sint64 middle; + PHYSFS_uint32 dlen = (PHYSFS_uint32) strlen(path); + PHYSFS_sint64 retval = -1; + const char *name; + int rc; + + if (*path == '\0') /* root dir? */ + return 0; + + if ((dlen > 0) && (path[dlen - 1] == '/')) /* ignore trailing slash. */ + dlen--; + + while (lo <= hi) + { + middle = lo + ((hi - lo) / 2); + name = info->entries[middle].name; + rc = strncmp(path, name, dlen); + if (rc == 0) + { + char ch = name[dlen]; + if ('/' < ch) /* make sure this isn't just a substr match. */ + rc = -1; + else if ('/' > ch) + rc = 1; + else + { + if (stop_on_first_find) /* Just checking dir's existance? */ + return middle; + + if (name[dlen + 1] == '\0') /* Skip initial dir entry. */ + return (middle + 1); + + /* there might be more entries earlier in the list. */ + retval = middle; + hi = middle - 1; + } /* else */ + } /* if */ + + if (rc > 0) + lo = middle + 1; + else + hi = middle - 1; + } /* while */ + + return retval; +} /* zip_find_start_of_dir */ + + +/* + * Moved to seperate function so we can use alloca then immediately throw + * away the allocated stack space... + */ +static void doEnumCallback(PHYSFS_EnumFilesCallback cb, void *callbackdata, + const char *odir, const char *str, PHYSFS_sint32 ln) +{ + char *newstr = __PHYSFS_smallAlloc(ln + 1); + if (newstr == NULL) + return; + + memcpy(newstr, str, ln); + newstr[ln] = '\0'; + cb(callbackdata, odir, newstr); + __PHYSFS_smallFree(newstr); +} /* doEnumCallback */ + + +static void ZIP_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata) +{ + ZIPinfo *info = ((ZIPinfo *) opaque); + PHYSFS_sint32 dlen, dlen_inc; + PHYSFS_sint64 i, max; + + i = zip_find_start_of_dir(info, dname, 0); + if (i == -1) /* no such directory. */ + return; + + dlen = (PHYSFS_sint32) strlen(dname); + if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */ + dlen--; + + dlen_inc = ((dlen > 0) ? 1 : 0) + dlen; + max = (PHYSFS_sint64) info->entryCount; + while (i < max) + { + char *e = info->entries[i].name; + if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/'))) + break; /* past end of this dir; we're done. */ + + if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i]))) + i++; + else + { + char *add = e + dlen_inc; + char *ptr = strchr(add, '/'); + PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add)); + doEnumCallback(cb, callbackdata, origdir, add, ln); + ln += dlen_inc; /* point past entry to children... */ + + /* increment counter and skip children of subdirs... */ + while ((++i < max) && (ptr != NULL)) + { + char *e_new = info->entries[i].name; + if ((strncmp(e, e_new, ln) != 0) || (e_new[ln] != '/')) + break; + } /* while */ + } /* else */ + } /* while */ +} /* ZIP_enumerateFiles */ + + +static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry) +{ + int success; + PHYSFS_Io *retval = io->duplicate(io); + BAIL_IF_MACRO(!retval, ERRPASS, NULL); + + /* !!! FIXME: if you open a dir here, it should bail ERR_NOT_A_FILE */ + + /* (inf) can be NULL if we already resolved. */ + success = (inf == NULL) || zip_resolve(retval, inf, entry); + if (success) + { + PHYSFS_sint64 offset; + offset = ((entry->symlink) ? entry->symlink->offset : entry->offset); + success = retval->seek(retval, offset); + } /* if */ + + if (!success) + { + retval->destroy(retval); + retval = NULL; + } /* if */ + + return retval; +} /* zip_get_io */ + + +static PHYSFS_Io *ZIP_openRead(PHYSFS_Dir *opaque, const char *fnm, + int *fileExists) +{ + PHYSFS_Io *retval = NULL; + ZIPinfo *info = (ZIPinfo *) opaque; + ZIPentry *entry = zip_find_entry(info, fnm, NULL); + ZIPfileinfo *finfo = NULL; + + *fileExists = (entry != NULL); + BAIL_IF_MACRO(!entry, ERRPASS, NULL); + + retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed); + + finfo = (ZIPfileinfo *) allocator.Malloc(sizeof (ZIPfileinfo)); + GOTO_IF_MACRO(!finfo, PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed); + memset(finfo, '\0', sizeof (ZIPfileinfo)); + + finfo->io = zip_get_io(info->io, info, entry); + GOTO_IF_MACRO(!finfo->io, ERRPASS, ZIP_openRead_failed); + finfo->entry = ((entry->symlink != NULL) ? entry->symlink : entry); + initializeZStream(&finfo->stream); + + if (finfo->entry->compression_method != COMPMETH_NONE) + { + finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE); + if (!finfo->buffer) + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, ZIP_openRead_failed); + else if (zlib_err(inflateInit2(&finfo->stream, -MAX_WBITS)) != Z_OK) + goto ZIP_openRead_failed; + } /* if */ + + memcpy(retval, &ZIP_Io, sizeof (PHYSFS_Io)); + retval->opaque = finfo; + + return retval; + +ZIP_openRead_failed: + if (finfo != NULL) + { + if (finfo->io != NULL) + finfo->io->destroy(finfo->io); + + if (finfo->buffer != NULL) + { + allocator.Free(finfo->buffer); + inflateEnd(&finfo->stream); + } /* if */ + + allocator.Free(finfo); + } /* if */ + + if (retval != NULL) + allocator.Free(retval); + + return NULL; +} /* ZIP_openRead */ + + +static PHYSFS_Io *ZIP_openWrite(PHYSFS_Dir *opaque, const char *filename) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* ZIP_openWrite */ + + +static PHYSFS_Io *ZIP_openAppend(PHYSFS_Dir *opaque, const char *filename) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, NULL); +} /* ZIP_openAppend */ + + +static void ZIP_closeArchive(PHYSFS_Dir *opaque) +{ + ZIPinfo *zi = (ZIPinfo *) (opaque); + zi->io->destroy(zi->io); + zip_free_entries(zi->entries, zi->entryCount); + allocator.Free(zi); +} /* ZIP_closeArchive */ + + +static int ZIP_remove(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* ZIP_remove */ + + +static int ZIP_mkdir(PHYSFS_Dir *opaque, const char *name) +{ + BAIL_MACRO(PHYSFS_ERR_READ_ONLY, 0); +} /* ZIP_mkdir */ + + +static int ZIP_stat(PHYSFS_Dir *opaque, const char *filename, int *exists, + PHYSFS_Stat *stat) +{ + int isDir = 0; + const ZIPinfo *info = (const ZIPinfo *) opaque; + const ZIPentry *entry = zip_find_entry(info, filename, &isDir); + + /* !!! FIXME: does this need to resolve entries here? */ + + *exists = isDir || (entry != 0); + if (!*exists) + return 0; + + if (isDir) + { + stat->filesize = 0; + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + } /* if */ + + else if (zip_entry_is_symlink(entry)) + { + stat->filesize = 0; + stat->filetype = PHYSFS_FILETYPE_SYMLINK; + } /* else if */ + + else + { + stat->filesize = (PHYSFS_sint64) entry->uncompressed_size; + stat->filetype = PHYSFS_FILETYPE_REGULAR; + } /* else */ + + stat->modtime = ((entry) ? entry->last_mod_time : 0); + stat->createtime = stat->modtime; + stat->accesstime = 0; + stat->readonly = 1; /* .zip files are always read only */ + + return 1; +} /* ZIP_stat */ + + +const PHYSFS_Archiver __PHYSFS_Archiver_ZIP = +{ + { + "ZIP", + "PkZip/WinZip/Info-Zip compatible", + "Ryan C. Gordon ", + "http://icculus.org/physfs/", + }, + ZIP_openArchive, /* openArchive() method */ + ZIP_enumerateFiles, /* enumerateFiles() method */ + ZIP_openRead, /* openRead() method */ + ZIP_openWrite, /* openWrite() method */ + ZIP_openAppend, /* openAppend() method */ + ZIP_remove, /* remove() method */ + ZIP_mkdir, /* mkdir() method */ + ZIP_closeArchive, /* closeArchive() method */ + ZIP_stat /* stat() method */ +}; + +#endif /* defined PHYSFS_SUPPORTS_ZIP */ + +/* end of zip.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,2744 @@ +/** + * PhysicsFS; a portable, flexible file i/o abstraction. + * + * Documentation is in physfs.h. It's verbose, honest. :) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +/* !!! FIXME: ERR_PAST_EOF shouldn't trigger for reads. Just return zero. */ +/* !!! FIXME: use snprintf(), not sprintf(). */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + + +typedef struct __PHYSFS_DIRHANDLE__ +{ + void *opaque; /* Instance data unique to the archiver. */ + char *dirName; /* Path to archive in platform-dependent notation. */ + char *mountPoint; /* Mountpoint in virtual file tree. */ + const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */ + struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */ +} DirHandle; + + +typedef struct __PHYSFS_FILEHANDLE__ +{ + PHYSFS_Io *io; /* Instance data unique to the archiver for this file. */ + PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */ + const DirHandle *dirHandle; /* Archiver instance that created this */ + PHYSFS_uint8 *buffer; /* Buffer, if set (NULL otherwise). Don't touch! */ + PHYSFS_uint32 bufsize; /* Bufsize, if set (0 otherwise). Don't touch! */ + PHYSFS_uint32 buffill; /* Buffer fill size. Don't touch! */ + PHYSFS_uint32 bufpos; /* Buffer position. Don't touch! */ + struct __PHYSFS_FILEHANDLE__ *next; /* linked list stuff. */ +} FileHandle; + + +typedef struct __PHYSFS_ERRSTATETYPE__ +{ + void *tid; + PHYSFS_ErrorCode code; + struct __PHYSFS_ERRSTATETYPE__ *next; +} ErrState; + + +/* The various i/o drivers...some of these may not be compiled in. */ +extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP; +extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA; +extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP; +extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK; +extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG; +extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL; +extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD; +extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR; +extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660; + +static const PHYSFS_Archiver *staticArchivers[] = +{ +#if PHYSFS_SUPPORTS_ZIP + &__PHYSFS_Archiver_ZIP, +#endif +#if PHYSFS_SUPPORTS_7Z + &__PHYSFS_Archiver_LZMA, +#endif +#if PHYSFS_SUPPORTS_GRP + &__PHYSFS_Archiver_GRP, +#endif +#if PHYSFS_SUPPORTS_QPAK + &__PHYSFS_Archiver_QPAK, +#endif +#if PHYSFS_SUPPORTS_HOG + &__PHYSFS_Archiver_HOG, +#endif +#if PHYSFS_SUPPORTS_MVL + &__PHYSFS_Archiver_MVL, +#endif +#if PHYSFS_SUPPORTS_WAD + &__PHYSFS_Archiver_WAD, +#endif +#if PHYSFS_SUPPORTS_ISO9660 + &__PHYSFS_Archiver_ISO9660, +#endif + NULL +}; + + + +/* General PhysicsFS state ... */ +static int initialized = 0; +static ErrState *errorStates = NULL; +static DirHandle *searchPath = NULL; +static DirHandle *writeDir = NULL; +static FileHandle *openWriteList = NULL; +static FileHandle *openReadList = NULL; +static char *baseDir = NULL; +static char *userDir = NULL; +static char *prefDir = NULL; +static int allowSymLinks = 0; +static const PHYSFS_Archiver **archivers = NULL; +static const PHYSFS_ArchiveInfo **archiveInfo = NULL; + +/* mutexes ... */ +static void *errorLock = NULL; /* protects error message list. */ +static void *stateLock = NULL; /* protects other PhysFS static state. */ + +/* allocator ... */ +static int externalAllocator = 0; +PHYSFS_Allocator allocator; + + +/* PHYSFS_Io implementation for i/o to physical filesystem... */ + +/* !!! FIXME: maybe refcount the paths in a string pool? */ +typedef struct __PHYSFS_NativeIoInfo +{ + void *handle; + const char *path; + int mode; /* 'r', 'w', or 'a' */ +} NativeIoInfo; + +static PHYSFS_sint64 nativeIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_platformRead(info->handle, buf, len); +} /* nativeIo_read */ + +static PHYSFS_sint64 nativeIo_write(PHYSFS_Io *io, const void *buffer, + PHYSFS_uint64 len) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_platformWrite(info->handle, buffer, len); +} /* nativeIo_write */ + +static int nativeIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_platformSeek(info->handle, offset); +} /* nativeIo_seek */ + +static PHYSFS_sint64 nativeIo_tell(PHYSFS_Io *io) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_platformTell(info->handle); +} /* nativeIo_tell */ + +static PHYSFS_sint64 nativeIo_length(PHYSFS_Io *io) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_platformFileLength(info->handle); +} /* nativeIo_length */ + +static PHYSFS_Io *nativeIo_duplicate(PHYSFS_Io *io) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + return __PHYSFS_createNativeIo(info->path, info->mode); +} /* nativeIo_duplicate */ + +static int nativeIo_flush(PHYSFS_Io *io) +{ + return __PHYSFS_platformFlush(io->opaque); +} /* nativeIo_flush */ + +static void nativeIo_destroy(PHYSFS_Io *io) +{ + NativeIoInfo *info = (NativeIoInfo *) io->opaque; + __PHYSFS_platformClose(info->handle); + allocator.Free((void *) info->path); + allocator.Free(info); + allocator.Free(io); +} /* nativeIo_destroy */ + +static const PHYSFS_Io __PHYSFS_nativeIoInterface = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + nativeIo_read, + nativeIo_write, + nativeIo_seek, + nativeIo_tell, + nativeIo_length, + nativeIo_duplicate, + nativeIo_flush, + nativeIo_destroy +}; + +PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode) +{ + PHYSFS_Io *io = NULL; + NativeIoInfo *info = NULL; + void *handle = NULL; + char *pathdup = NULL; + + assert((mode == 'r') || (mode == 'w') || (mode == 'a')); + + io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed); + info = (NativeIoInfo *) allocator.Malloc(sizeof (NativeIoInfo)); + GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed); + pathdup = (char *) allocator.Malloc(strlen(path) + 1); + GOTO_IF_MACRO(!pathdup, PHYSFS_ERR_OUT_OF_MEMORY, createNativeIo_failed); + + if (mode == 'r') + handle = __PHYSFS_platformOpenRead(path); + else if (mode == 'w') + handle = __PHYSFS_platformOpenWrite(path); + else if (mode == 'a') + handle = __PHYSFS_platformOpenAppend(path); + + GOTO_IF_MACRO(!handle, ERRPASS, createNativeIo_failed); + + strcpy(pathdup, path); + info->handle = handle; + info->path = pathdup; + info->mode = mode; + memcpy(io, &__PHYSFS_nativeIoInterface, sizeof (*io)); + io->opaque = info; + return io; + +createNativeIo_failed: + if (handle != NULL) __PHYSFS_platformClose(handle); + if (pathdup != NULL) allocator.Free(pathdup); + if (info != NULL) allocator.Free(info); + if (io != NULL) allocator.Free(io); + return NULL; +} /* __PHYSFS_createNativeIo */ + + +/* PHYSFS_Io implementation for i/o to a memory buffer... */ + +typedef struct __PHYSFS_MemoryIoInfo +{ + const PHYSFS_uint8 *buf; + PHYSFS_uint64 len; + PHYSFS_uint64 pos; + PHYSFS_Io *parent; + volatile PHYSFS_uint32 refcount; + void (*destruct)(void *); +} MemoryIoInfo; + +static PHYSFS_sint64 memoryIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) +{ + MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + const PHYSFS_uint64 avail = info->len - info->pos; + assert(avail <= info->len); + + if (avail == 0) + return 0; /* we're at EOF; nothing to do. */ + + if (len > avail) + len = avail; + + memcpy(buf, info->buf + info->pos, (size_t) len); + info->pos += len; + return len; +} /* memoryIo_read */ + +static PHYSFS_sint64 memoryIo_write(PHYSFS_Io *io, const void *buffer, + PHYSFS_uint64 len) +{ + BAIL_MACRO(PHYSFS_ERR_OPEN_FOR_READING, -1); +} /* memoryIo_write */ + +static int memoryIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + BAIL_IF_MACRO(offset > info->len, PHYSFS_ERR_PAST_EOF, 0); + info->pos = offset; + return 1; +} /* memoryIo_seek */ + +static PHYSFS_sint64 memoryIo_tell(PHYSFS_Io *io) +{ + const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + return (PHYSFS_sint64) info->pos; +} /* memoryIo_tell */ + +static PHYSFS_sint64 memoryIo_length(PHYSFS_Io *io) +{ + const MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + return (PHYSFS_sint64) info->len; +} /* memoryIo_length */ + +static PHYSFS_Io *memoryIo_duplicate(PHYSFS_Io *io) +{ + MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + MemoryIoInfo *newinfo = NULL; + PHYSFS_Io *parent = info->parent; + PHYSFS_Io *retval = NULL; + + /* avoid deep copies. */ + assert((!parent) || (!((MemoryIoInfo *) parent->opaque)->parent) ); + + /* share the buffer between duplicates. */ + if (parent != NULL) /* dup the parent, increment its refcount. */ + return parent->duplicate(parent); + + /* we're the parent. */ + + retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + newinfo = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo)); + if (!newinfo) + { + allocator.Free(retval); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + /* !!! FIXME: want lockless atomic increment. */ + __PHYSFS_platformGrabMutex(stateLock); + info->refcount++; + __PHYSFS_platformReleaseMutex(stateLock); + + memset(newinfo, '\0', sizeof (*info)); + newinfo->buf = info->buf; + newinfo->len = info->len; + newinfo->pos = 0; + newinfo->parent = io; + newinfo->refcount = 0; + newinfo->destruct = NULL; + + memcpy(retval, io, sizeof (*retval)); + retval->opaque = newinfo; + return retval; +} /* memoryIo_duplicate */ + +static int memoryIo_flush(PHYSFS_Io *io) { return 1; /* it's read-only. */ } + +static void memoryIo_destroy(PHYSFS_Io *io) +{ + MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + PHYSFS_Io *parent = info->parent; + int should_die = 0; + + if (parent != NULL) + { + assert(info->buf == ((MemoryIoInfo *) info->parent->opaque)->buf); + assert(info->len == ((MemoryIoInfo *) info->parent->opaque)->len); + assert(info->refcount == 0); + assert(info->destruct == NULL); + allocator.Free(info); + allocator.Free(io); + parent->destroy(parent); /* decrements refcount. */ + return; + } /* if */ + + /* we _are_ the parent. */ + assert(info->refcount > 0); /* even in a race, we hold a reference. */ + + /* !!! FIXME: want lockless atomic decrement. */ + __PHYSFS_platformGrabMutex(stateLock); + info->refcount--; + should_die = (info->refcount == 0); + __PHYSFS_platformReleaseMutex(stateLock); + + if (should_die) + { + void (*destruct)(void *) = info->destruct; + void *buf = (void *) info->buf; + io->opaque = NULL; /* kill this here in case of race. */ + allocator.Free(info); + allocator.Free(io); + if (destruct != NULL) + destruct(buf); + } /* if */ +} /* memoryIo_destroy */ + + +static const PHYSFS_Io __PHYSFS_memoryIoInterface = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + memoryIo_read, + memoryIo_write, + memoryIo_seek, + memoryIo_tell, + memoryIo_length, + memoryIo_duplicate, + memoryIo_flush, + memoryIo_destroy +}; + +PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len, + void (*destruct)(void *)) +{ + PHYSFS_Io *io = NULL; + MemoryIoInfo *info = NULL; + + io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + GOTO_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed); + info = (MemoryIoInfo *) allocator.Malloc(sizeof (MemoryIoInfo)); + GOTO_IF_MACRO(!info, PHYSFS_ERR_OUT_OF_MEMORY, createMemoryIo_failed); + + memset(info, '\0', sizeof (*info)); + info->buf = (const PHYSFS_uint8 *) buf; + info->len = len; + info->pos = 0; + info->parent = NULL; + info->refcount = 1; + info->destruct = destruct; + + memcpy(io, &__PHYSFS_memoryIoInterface, sizeof (*io)); + io->opaque = info; + return io; + +createMemoryIo_failed: + if (info != NULL) allocator.Free(info); + if (io != NULL) allocator.Free(io); + return NULL; +} /* __PHYSFS_createMemoryIo */ + + +/* PHYSFS_Io implementation for i/o to a PHYSFS_File... */ + +static PHYSFS_sint64 handleIo_read(PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) +{ + return PHYSFS_readBytes((PHYSFS_File *) io->opaque, buf, len); +} /* handleIo_read */ + +static PHYSFS_sint64 handleIo_write(PHYSFS_Io *io, const void *buffer, + PHYSFS_uint64 len) +{ + return PHYSFS_writeBytes((PHYSFS_File *) io->opaque, buffer, len); +} /* handleIo_write */ + +static int handleIo_seek(PHYSFS_Io *io, PHYSFS_uint64 offset) +{ + return PHYSFS_seek((PHYSFS_File *) io->opaque, offset); +} /* handleIo_seek */ + +static PHYSFS_sint64 handleIo_tell(PHYSFS_Io *io) +{ + return PHYSFS_tell((PHYSFS_File *) io->opaque); +} /* handleIo_tell */ + +static PHYSFS_sint64 handleIo_length(PHYSFS_Io *io) +{ + return PHYSFS_fileLength((PHYSFS_File *) io->opaque); +} /* handleIo_length */ + +static PHYSFS_Io *handleIo_duplicate(PHYSFS_Io *io) +{ + /* + * There's no duplicate at the PHYSFS_File level, so we break the + * abstraction. We're allowed to: we're physfs.c! + */ + FileHandle *origfh = (FileHandle *) io->opaque; + FileHandle *newfh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + PHYSFS_Io *retval = NULL; + + GOTO_IF_MACRO(!newfh, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed); + memset(newfh, '\0', sizeof (*newfh)); + + retval = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + GOTO_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed); + +#if 0 /* we don't buffer the duplicate, at least not at the moment. */ + if (origfh->buffer != NULL) + { + newfh->buffer = (PHYSFS_uint8 *) allocator.Malloc(origfh->bufsize); + if (!newfh->buffer) + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, handleIo_dupe_failed); + newfh->bufsize = origfh->bufsize; + } /* if */ +#endif + + newfh->io = origfh->io->duplicate(origfh->io); + GOTO_IF_MACRO(!newfh->io, ERRPASS, handleIo_dupe_failed); + + newfh->forReading = origfh->forReading; + newfh->dirHandle = origfh->dirHandle; + + __PHYSFS_platformGrabMutex(stateLock); + if (newfh->forReading) + { + newfh->next = openReadList; + openReadList = newfh; + } /* if */ + else + { + newfh->next = openWriteList; + openWriteList = newfh; + } /* else */ + __PHYSFS_platformReleaseMutex(stateLock); + + memcpy(retval, io, sizeof (PHYSFS_Io)); + retval->opaque = newfh; + return retval; + +handleIo_dupe_failed: + if (newfh) + { + if (newfh->io != NULL) newfh->io->destroy(newfh->io); + if (newfh->buffer != NULL) allocator.Free(newfh->buffer); + allocator.Free(newfh); + } /* if */ + + return NULL; +} /* handleIo_duplicate */ + +static int handleIo_flush(PHYSFS_Io *io) +{ + return PHYSFS_flush((PHYSFS_File *) io->opaque); +} /* handleIo_flush */ + +static void handleIo_destroy(PHYSFS_Io *io) +{ + if (io->opaque != NULL) + PHYSFS_close((PHYSFS_File *) io->opaque); + allocator.Free(io); +} /* handleIo_destroy */ + +static const PHYSFS_Io __PHYSFS_handleIoInterface = +{ + CURRENT_PHYSFS_IO_API_VERSION, NULL, + handleIo_read, + handleIo_write, + handleIo_seek, + handleIo_tell, + handleIo_length, + handleIo_duplicate, + handleIo_flush, + handleIo_destroy +}; + +static PHYSFS_Io *__PHYSFS_createHandleIo(PHYSFS_File *f) +{ + PHYSFS_Io *io = (PHYSFS_Io *) allocator.Malloc(sizeof (PHYSFS_Io)); + BAIL_IF_MACRO(!io, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + memcpy(io, &__PHYSFS_handleIoInterface, sizeof (*io)); + io->opaque = f; + return io; +} /* __PHYSFS_createHandleIo */ + + +/* functions ... */ + +typedef struct +{ + char **list; + PHYSFS_uint32 size; + PHYSFS_ErrorCode errcode; +} EnumStringListCallbackData; + +static void enumStringListCallback(void *data, const char *str) +{ + void *ptr; + char *newstr; + EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data; + + if (pecd->errcode) + return; + + ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *)); + newstr = (char *) allocator.Malloc(strlen(str) + 1); + if (ptr != NULL) + pecd->list = (char **) ptr; + + if ((ptr == NULL) || (newstr == NULL)) + { + pecd->errcode = PHYSFS_ERR_OUT_OF_MEMORY; + pecd->list[pecd->size] = NULL; + PHYSFS_freeList(pecd->list); + return; + } /* if */ + + strcpy(newstr, str); + pecd->list[pecd->size] = newstr; + pecd->size++; +} /* enumStringListCallback */ + + +static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *)) +{ + EnumStringListCallbackData ecd; + memset(&ecd, '\0', sizeof (ecd)); + ecd.list = (char **) allocator.Malloc(sizeof (char *)); + BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + func(enumStringListCallback, &ecd); + + if (ecd.errcode) + { + __PHYSFS_setError(ecd.errcode); + return NULL; + } /* if */ + + ecd.list[ecd.size] = NULL; + return ecd.list; +} /* doEnumStringList */ + + +static void __PHYSFS_bubble_sort(void *a, size_t lo, size_t hi, + int (*cmpfn)(void *, size_t, size_t), + void (*swapfn)(void *, size_t, size_t)) +{ + size_t i; + int sorted; + + do + { + sorted = 1; + for (i = lo; i < hi; i++) + { + if (cmpfn(a, i, i + 1) > 0) + { + swapfn(a, i, i + 1); + sorted = 0; + } /* if */ + } /* for */ + } while (!sorted); +} /* __PHYSFS_bubble_sort */ + + +static void __PHYSFS_quick_sort(void *a, size_t lo, size_t hi, + int (*cmpfn)(void *, size_t, size_t), + void (*swapfn)(void *, size_t, size_t)) +{ + size_t i; + size_t j; + size_t v; + + if ((hi - lo) <= PHYSFS_QUICKSORT_THRESHOLD) + __PHYSFS_bubble_sort(a, lo, hi, cmpfn, swapfn); + else + { + i = (hi + lo) / 2; + + if (cmpfn(a, lo, i) > 0) swapfn(a, lo, i); + if (cmpfn(a, lo, hi) > 0) swapfn(a, lo, hi); + if (cmpfn(a, i, hi) > 0) swapfn(a, i, hi); + + j = hi - 1; + swapfn(a, i, j); + i = lo; + v = j; + while (1) + { + while(cmpfn(a, ++i, v) < 0) { /* do nothing */ } + while(cmpfn(a, --j, v) > 0) { /* do nothing */ } + if (j < i) + break; + swapfn(a, i, j); + } /* while */ + if (i != (hi-1)) + swapfn(a, i, hi-1); + __PHYSFS_quick_sort(a, lo, j, cmpfn, swapfn); + __PHYSFS_quick_sort(a, i+1, hi, cmpfn, swapfn); + } /* else */ +} /* __PHYSFS_quick_sort */ + + +void __PHYSFS_sort(void *entries, size_t max, + int (*cmpfn)(void *, size_t, size_t), + void (*swapfn)(void *, size_t, size_t)) +{ + /* + * Quicksort w/ Bubblesort fallback algorithm inspired by code from here: + * http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html + */ + if (max > 0) + __PHYSFS_quick_sort(entries, 0, max - 1, cmpfn, swapfn); +} /* __PHYSFS_sort */ + + +static ErrState *findErrorForCurrentThread(void) +{ + ErrState *i; + void *tid; + + if (errorLock != NULL) + __PHYSFS_platformGrabMutex(errorLock); + + if (errorStates != NULL) + { + tid = __PHYSFS_platformGetThreadID(); + + for (i = errorStates; i != NULL; i = i->next) + { + if (i->tid == tid) + { + if (errorLock != NULL) + __PHYSFS_platformReleaseMutex(errorLock); + return i; + } /* if */ + } /* for */ + } /* if */ + + if (errorLock != NULL) + __PHYSFS_platformReleaseMutex(errorLock); + + return NULL; /* no error available. */ +} /* findErrorForCurrentThread */ + + +void __PHYSFS_setError(const PHYSFS_ErrorCode errcode) +{ + ErrState *err; + + if (!errcode) + return; + + err = findErrorForCurrentThread(); + if (err == NULL) + { + err = (ErrState *) allocator.Malloc(sizeof (ErrState)); + if (err == NULL) + return; /* uhh...? */ + + memset(err, '\0', sizeof (ErrState)); + err->tid = __PHYSFS_platformGetThreadID(); + + if (errorLock != NULL) + __PHYSFS_platformGrabMutex(errorLock); + + err->next = errorStates; + errorStates = err; + + if (errorLock != NULL) + __PHYSFS_platformReleaseMutex(errorLock); + } /* if */ + + err->code = errcode; +} /* __PHYSFS_setError */ + + +PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void) +{ + ErrState *err = findErrorForCurrentThread(); + const PHYSFS_ErrorCode retval = (err) ? err->code : PHYSFS_ERR_OK; + if (err) + err->code = PHYSFS_ERR_OK; + return retval; +} /* PHYSFS_getLastErrorCode */ + + +PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code) +{ + switch (code) + { + case PHYSFS_ERR_OK: return "no error"; + case PHYSFS_ERR_OTHER_ERROR: return "unknown error"; + case PHYSFS_ERR_OUT_OF_MEMORY: return "out of memory"; + case PHYSFS_ERR_NOT_INITIALIZED: return "not initialized"; + case PHYSFS_ERR_IS_INITIALIZED: return "already initialized"; + case PHYSFS_ERR_ARGV0_IS_NULL: return "argv[0] is NULL"; + case PHYSFS_ERR_UNSUPPORTED: return "unsupported"; + case PHYSFS_ERR_PAST_EOF: return "past end of file"; + case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open"; + case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument"; + case PHYSFS_ERR_NOT_MOUNTED: return "not mounted"; + case PHYSFS_ERR_NO_SUCH_PATH: return "no such path"; + case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden"; + case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set"; + case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading"; + case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing"; + case PHYSFS_ERR_NOT_A_FILE: return "not a file"; + case PHYSFS_ERR_READ_ONLY: return "read-only filesystem"; + case PHYSFS_ERR_CORRUPT: return "corrupted"; + case PHYSFS_ERR_SYMLINK_LOOP: return "infinite symbolic link loop"; + case PHYSFS_ERR_IO: return "i/o error"; + case PHYSFS_ERR_PERMISSION: return "permission denied"; + case PHYSFS_ERR_NO_SPACE: return "no space available for writing"; + case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure"; + case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs"; + case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty"; + case PHYSFS_ERR_OS_ERROR: return "OS reported an error"; + } /* switch */ + + return NULL; /* don't know this error code. */ +} /* PHYSFS_getErrorByCode */ + + +void PHYSFS_setErrorCode(PHYSFS_ErrorCode code) +{ + __PHYSFS_setError(code); +} /* PHYSFS_setErrorCode */ + + +const char *PHYSFS_getLastError(void) +{ + const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode(); + return (err) ? PHYSFS_getErrorByCode(err) : NULL; +} /* PHYSFS_getLastError */ + + +/* MAKE SURE that errorLock is held before calling this! */ +static void freeErrorStates(void) +{ + ErrState *i; + ErrState *next; + + for (i = errorStates; i != NULL; i = next) + { + next = i->next; + allocator.Free(i); + } /* for */ + + errorStates = NULL; +} /* freeErrorStates */ + + +void PHYSFS_getLinkedVersion(PHYSFS_Version *ver) +{ + if (ver != NULL) + { + ver->major = PHYSFS_VER_MAJOR; + ver->minor = PHYSFS_VER_MINOR; + ver->patch = PHYSFS_VER_PATCH; + } /* if */ +} /* PHYSFS_getLinkedVersion */ + + +static const char *find_filename_extension(const char *fname) +{ + const char *retval = NULL; + if (fname != NULL) + { + const char *p = strchr(fname, '.'); + retval = p; + + while (p != NULL) + { + p = strchr(p + 1, '.'); + if (p != NULL) + retval = p; + } /* while */ + + if (retval != NULL) + retval++; /* skip '.' */ + } /* if */ + + return retval; +} /* find_filename_extension */ + + +static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs, + const char *d, int forWriting) +{ + DirHandle *retval = NULL; + void *opaque = NULL; + + if (io != NULL) + BAIL_IF_MACRO(!io->seek(io, 0), ERRPASS, NULL); + + opaque = funcs->openArchive(io, d, forWriting); + if (opaque != NULL) + { + retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle)); + if (retval == NULL) + funcs->closeArchive(opaque); + else + { + memset(retval, '\0', sizeof (DirHandle)); + retval->mountPoint = NULL; + retval->funcs = funcs; + retval->opaque = opaque; + } /* else */ + } /* if */ + + return retval; +} /* tryOpenDir */ + + +static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) +{ + DirHandle *retval = NULL; + const PHYSFS_Archiver **i; + const char *ext; + + assert((io != NULL) || (d != NULL)); + + if (io == NULL) + { + /* DIR gets first shot (unlike the rest, it doesn't deal with files). */ + retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting); + if (retval != NULL) + return retval; + + io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r'); + BAIL_IF_MACRO(!io, ERRPASS, 0); + } /* if */ + + ext = find_filename_extension(d); + if (ext != NULL) + { + /* Look for archivers with matching file extensions first... */ + for (i = archivers; (*i != NULL) && (retval == NULL); i++) + { + if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0) + retval = tryOpenDir(io, *i, d, forWriting); + } /* for */ + + /* failing an exact file extension match, try all the others... */ + for (i = archivers; (*i != NULL) && (retval == NULL); i++) + { + if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0) + retval = tryOpenDir(io, *i, d, forWriting); + } /* for */ + } /* if */ + + else /* no extension? Try them all. */ + { + for (i = archivers; (*i != NULL) && (retval == NULL); i++) + retval = tryOpenDir(io, *i, d, forWriting); + } /* else */ + + BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL); + return retval; +} /* openDirectory */ + + +/* + * Make a platform-independent path string sane. Doesn't actually check the + * file hierarchy, it just cleans up the string. + * (dst) must be a buffer at least as big as (src), as this is where the + * cleaned up string is deposited. + * If there are illegal bits in the path (".." entries, etc) then we + * return zero and (dst) is undefined. Non-zero if the path was sanitized. + */ +static int sanitizePlatformIndependentPath(const char *src, char *dst) +{ + char *prev; + char ch; + + while (*src == '/') /* skip initial '/' chars... */ + src++; + + prev = dst; + do + { + ch = *(src++); + + if ((ch == ':') || (ch == '\\')) /* illegal chars in a physfs path. */ + BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0); + + if (ch == '/') /* path separator. */ + { + *dst = '\0'; /* "." and ".." are illegal pathnames. */ + if ((strcmp(prev, ".") == 0) || (strcmp(prev, "..") == 0)) + BAIL_MACRO(PHYSFS_ERR_BAD_FILENAME, 0); + + while (*src == '/') /* chop out doubles... */ + src++; + + if (*src == '\0') /* ends with a pathsep? */ + break; /* we're done, don't add final pathsep to dst. */ + + prev = dst + 1; + } /* if */ + + *(dst++) = ch; + } while (ch != '\0'); + + return 1; +} /* sanitizePlatformIndependentPath */ + + +/* + * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an + * output from sanitizePlatformIndependentPath(), so that it is in a known + * state. + * + * This only finds legitimate segments of a mountpoint. If the mountpoint is + * "/a/b/c" and (fname) is "/a/b/c", "/", or "/a/b/c/d", then the results are + * all zero. "/a/b" will succeed, though. + */ +static int partOfMountPoint(DirHandle *h, char *fname) +{ + /* !!! FIXME: This code feels gross. */ + int rc; + size_t len, mntpntlen; + + if (h->mountPoint == NULL) + return 0; + else if (*fname == '\0') + return 1; + + len = strlen(fname); + mntpntlen = strlen(h->mountPoint); + if (len > mntpntlen) /* can't be a subset of mountpoint. */ + return 0; + + /* if true, must be not a match or a complete match, but not a subset. */ + if ((len + 1) == mntpntlen) + return 0; + + rc = strncmp(fname, h->mountPoint, len); /* !!! FIXME: case insensitive? */ + if (rc != 0) + return 0; /* not a match. */ + + /* make sure /a/b matches /a/b/ and not /a/bc ... */ + return h->mountPoint[len] == '/'; +} /* partOfMountPoint */ + + +static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir, + const char *mountPoint, int forWriting) +{ + DirHandle *dirHandle = NULL; + char *tmpmntpnt = NULL; + + if (mountPoint != NULL) + { + const size_t len = strlen(mountPoint) + 1; + tmpmntpnt = (char *) __PHYSFS_smallAlloc(len); + GOTO_IF_MACRO(!tmpmntpnt, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle); + if (!sanitizePlatformIndependentPath(mountPoint, tmpmntpnt)) + goto badDirHandle; + mountPoint = tmpmntpnt; /* sanitized version. */ + } /* if */ + + dirHandle = openDirectory(io, newDir, forWriting); + GOTO_IF_MACRO(!dirHandle, ERRPASS, badDirHandle); + + if (newDir == NULL) + dirHandle->dirName = NULL; + else + { + dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1); + if (!dirHandle->dirName) + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle); + strcpy(dirHandle->dirName, newDir); + } /* else */ + + if ((mountPoint != NULL) && (*mountPoint != '\0')) + { + dirHandle->mountPoint = (char *)allocator.Malloc(strlen(mountPoint)+2); + if (!dirHandle->mountPoint) + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle); + strcpy(dirHandle->mountPoint, mountPoint); + strcat(dirHandle->mountPoint, "/"); + } /* if */ + + __PHYSFS_smallFree(tmpmntpnt); + return dirHandle; + +badDirHandle: + if (dirHandle != NULL) + { + dirHandle->funcs->closeArchive(dirHandle->opaque); + allocator.Free(dirHandle->dirName); + allocator.Free(dirHandle->mountPoint); + allocator.Free(dirHandle); + } /* if */ + + __PHYSFS_smallFree(tmpmntpnt); + return NULL; +} /* createDirHandle */ + + +/* MAKE SURE you've got the stateLock held before calling this! */ +static int freeDirHandle(DirHandle *dh, FileHandle *openList) +{ + FileHandle *i; + + if (dh == NULL) + return 1; + + for (i = openList; i != NULL; i = i->next) + BAIL_IF_MACRO(i->dirHandle == dh, PHYSFS_ERR_FILES_STILL_OPEN, 0); + + dh->funcs->closeArchive(dh->opaque); + allocator.Free(dh->dirName); + allocator.Free(dh->mountPoint); + allocator.Free(dh); + return 1; +} /* freeDirHandle */ + + +static char *calculateBaseDir(const char *argv0) +{ + const char dirsep = __PHYSFS_platformDirSeparator; + char *retval = NULL; + char *ptr = NULL; + + /* Give the platform layer first shot at this. */ + retval = __PHYSFS_platformCalcBaseDir(argv0); + if (retval != NULL) + return retval; + + /* We need argv0 to go on. */ + BAIL_IF_MACRO(argv0 == NULL, PHYSFS_ERR_ARGV0_IS_NULL, NULL); + + ptr = strrchr(argv0, dirsep); + if (ptr != NULL) + { + const size_t size = ((size_t) (ptr - argv0)) + 1; + retval = (char *) allocator.Malloc(size + 1); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + memcpy(retval, argv0, size); + retval[size] = '\0'; + return retval; + } /* if */ + + /* argv0 wasn't helpful. */ + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, NULL); +} /* calculateBaseDir */ + + +static int initializeMutexes(void) +{ + errorLock = __PHYSFS_platformCreateMutex(); + if (errorLock == NULL) + goto initializeMutexes_failed; + + stateLock = __PHYSFS_platformCreateMutex(); + if (stateLock == NULL) + goto initializeMutexes_failed; + + return 1; /* success. */ + +initializeMutexes_failed: + if (errorLock != NULL) + __PHYSFS_platformDestroyMutex(errorLock); + + if (stateLock != NULL) + __PHYSFS_platformDestroyMutex(stateLock); + + errorLock = stateLock = NULL; + return 0; /* failed. */ +} /* initializeMutexes */ + + +static void setDefaultAllocator(void); + +static int initStaticArchivers(void) +{ + const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers); + const size_t len = numStaticArchivers * sizeof (void *); + size_t i; + + assert(numStaticArchivers > 0); /* seriously, none at all?! */ + assert(staticArchivers[numStaticArchivers - 1] == NULL); + + archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len); + BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0); + archivers = (const PHYSFS_Archiver **) allocator.Malloc(len); + BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + for (i = 0; i < numStaticArchivers - 1; i++) + archiveInfo[i] = &staticArchivers[i]->info; + archiveInfo[numStaticArchivers - 1] = NULL; + + memcpy(archivers, staticArchivers, len); + + return 1; +} /* initStaticArchivers */ + + +static int doDeinit(void); + +int PHYSFS_init(const char *argv0) +{ + BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0); + + if (!externalAllocator) + setDefaultAllocator(); + + if ((allocator.Init != NULL) && (!allocator.Init())) return 0; + + if (!__PHYSFS_platformInit()) + { + if (allocator.Deinit != NULL) allocator.Deinit(); + return 0; + } /* if */ + + /* everything below here can be cleaned up safely by doDeinit(). */ + + if (!initializeMutexes()) goto initFailed; + + baseDir = calculateBaseDir(argv0); + if (!baseDir) goto initFailed; + + userDir = __PHYSFS_platformCalcUserDir(); + if (!userDir) goto initFailed; + + /* Platform layer is required to append a dirsep. */ + assert(baseDir[strlen(baseDir) - 1] == __PHYSFS_platformDirSeparator); + assert(userDir[strlen(userDir) - 1] == __PHYSFS_platformDirSeparator); + + if (!initStaticArchivers()) goto initFailed; + + initialized = 1; + + /* This makes sure that the error subsystem is initialized. */ + __PHYSFS_setError(PHYSFS_getLastErrorCode()); + + return 1; + +initFailed: + doDeinit(); + return 0; +} /* PHYSFS_init */ + + +/* MAKE SURE you hold stateLock before calling this! */ +static int closeFileHandleList(FileHandle **list) +{ + FileHandle *i; + FileHandle *next = NULL; + + for (i = *list; i != NULL; i = next) + { + PHYSFS_Io *io = i->io; + next = i->next; + + if (!io->flush(io)) + { + *list = i; + return 0; + } /* if */ + + io->destroy(io); + allocator.Free(i); + } /* for */ + + *list = NULL; + return 1; +} /* closeFileHandleList */ + + +/* MAKE SURE you hold the stateLock before calling this! */ +static void freeSearchPath(void) +{ + DirHandle *i; + DirHandle *next = NULL; + + closeFileHandleList(&openReadList); + + if (searchPath != NULL) + { + for (i = searchPath; i != NULL; i = next) + { + next = i->next; + freeDirHandle(i, openReadList); + } /* for */ + searchPath = NULL; + } /* if */ +} /* freeSearchPath */ + + +static int doDeinit(void) +{ + BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0); + + closeFileHandleList(&openWriteList); + BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0); + + freeSearchPath(); + freeErrorStates(); + + if (baseDir != NULL) + { + allocator.Free(baseDir); + baseDir = NULL; + } /* if */ + + if (userDir != NULL) + { + allocator.Free(userDir); + userDir = NULL; + } /* if */ + + if (prefDir != NULL) + { + allocator.Free(prefDir); + prefDir = NULL; + } /* if */ + + if (archiveInfo != NULL) + { + allocator.Free(archiveInfo); + archiveInfo = NULL; + } /* if */ + + if (archivers != NULL) + { + allocator.Free(archivers); + archivers = NULL; + } /* if */ + + allowSymLinks = 0; + initialized = 0; + + if (errorLock) __PHYSFS_platformDestroyMutex(errorLock); + if (stateLock) __PHYSFS_platformDestroyMutex(stateLock); + + if (allocator.Deinit != NULL) + allocator.Deinit(); + + errorLock = stateLock = NULL; + return 1; +} /* doDeinit */ + + +int PHYSFS_deinit(void) +{ + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); + return doDeinit(); +} /* PHYSFS_deinit */ + + +int PHYSFS_isInit(void) +{ + return initialized; +} /* PHYSFS_isInit */ + + +const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) +{ + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL); + return archiveInfo; +} /* PHYSFS_supportedArchiveTypes */ + + +void PHYSFS_freeList(void *list) +{ + void **i; + if (list != NULL) + { + for (i = (void **) list; *i != NULL; i++) + allocator.Free(*i); + + allocator.Free(list); + } /* if */ +} /* PHYSFS_freeList */ + + +const char *PHYSFS_getDirSeparator(void) +{ + static char retval[2] = { __PHYSFS_platformDirSeparator, '\0' }; + return retval; +} /* PHYSFS_getDirSeparator */ + + +char **PHYSFS_getCdRomDirs(void) +{ + return doEnumStringList(__PHYSFS_platformDetectAvailableCDs); +} /* PHYSFS_getCdRomDirs */ + + +void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data) +{ + __PHYSFS_platformDetectAvailableCDs(callback, data); +} /* PHYSFS_getCdRomDirsCallback */ + + +const char *PHYSFS_getPrefDir(const char *org, const char *app) +{ + const char dirsep = __PHYSFS_platformDirSeparator; + PHYSFS_Stat statbuf; + char *ptr = NULL; + char *endstr = NULL; + int exists = 0; + + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(!org, PHYSFS_ERR_INVALID_ARGUMENT, NULL); + BAIL_IF_MACRO(*org == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL); + BAIL_IF_MACRO(!app, PHYSFS_ERR_INVALID_ARGUMENT, NULL); + BAIL_IF_MACRO(*app == '\0', PHYSFS_ERR_INVALID_ARGUMENT, NULL); + + allocator.Free(prefDir); + prefDir = __PHYSFS_platformCalcPrefDir(org, app); + BAIL_IF_MACRO(!prefDir, ERRPASS, NULL); + + assert(strlen(prefDir) > 0); + endstr = prefDir + (strlen(prefDir) - 1); + assert(*endstr == dirsep); + *endstr = '\0'; /* mask out the final dirsep for now. */ + + if (!__PHYSFS_platformStat(prefDir, &exists, &statbuf)) + { + for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep)) + { + *ptr = '\0'; + __PHYSFS_platformMkDir(prefDir); + *ptr = dirsep; + } /* for */ + + if (!__PHYSFS_platformMkDir(prefDir)) + { + allocator.Free(prefDir); + prefDir = NULL; + } /* if */ + } /* if */ + + *endstr = dirsep; /* readd the final dirsep. */ + + return prefDir; +} /* PHYSFS_getPrefDir */ + + +const char *PHYSFS_getBaseDir(void) +{ + return baseDir; /* this is calculated in PHYSFS_init()... */ +} /* PHYSFS_getBaseDir */ + + +const char *__PHYSFS_getUserDir(void) /* not deprecated internal version. */ +{ + return userDir; /* this is calculated in PHYSFS_init()... */ +} /* __PHYSFS_getUserDir */ + + +const char *PHYSFS_getUserDir(void) +{ + return __PHYSFS_getUserDir(); +} /* PHYSFS_getUserDir */ + + +const char *PHYSFS_getWriteDir(void) +{ + const char *retval = NULL; + + __PHYSFS_platformGrabMutex(stateLock); + if (writeDir != NULL) + retval = writeDir->dirName; + __PHYSFS_platformReleaseMutex(stateLock); + + return retval; +} /* PHYSFS_getWriteDir */ + + +int PHYSFS_setWriteDir(const char *newDir) +{ + int retval = 1; + + __PHYSFS_platformGrabMutex(stateLock); + + if (writeDir != NULL) + { + BAIL_IF_MACRO_MUTEX(!freeDirHandle(writeDir, openWriteList), ERRPASS, + stateLock, 0); + writeDir = NULL; + } /* if */ + + if (newDir != NULL) + { + /* !!! FIXME: PHYSFS_Io shouldn't be NULL */ + writeDir = createDirHandle(NULL, newDir, NULL, 1); + retval = (writeDir != NULL); + } /* if */ + + __PHYSFS_platformReleaseMutex(stateLock); + + return retval; +} /* PHYSFS_setWriteDir */ + + +static int doMount(PHYSFS_Io *io, const char *fname, + const char *mountPoint, int appendToPath) +{ + DirHandle *dh; + DirHandle *prev = NULL; + DirHandle *i; + + if (mountPoint == NULL) + mountPoint = "/"; + + __PHYSFS_platformGrabMutex(stateLock); + + if (fname != NULL) + { + for (i = searchPath; i != NULL; i = i->next) + { + /* already in search path? */ + if ((i->dirName != NULL) && (strcmp(fname, i->dirName) == 0)) + BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1); + prev = i; + } /* for */ + } /* if */ + + dh = createDirHandle(io, fname, mountPoint, 0); + BAIL_IF_MACRO_MUTEX(!dh, ERRPASS, stateLock, 0); + + if (appendToPath) + { + if (prev == NULL) + searchPath = dh; + else + prev->next = dh; + } /* if */ + else + { + dh->next = searchPath; + searchPath = dh; + } /* else */ + + __PHYSFS_platformReleaseMutex(stateLock); + return 1; +} /* doMount */ + + +int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, + const char *mountPoint, int appendToPath) +{ + BAIL_IF_MACRO(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0); + return doMount(io, fname, mountPoint, appendToPath); +} /* PHYSFS_mountIo */ + + +int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *), + const char *fname, const char *mountPoint, + int appendToPath) +{ + int retval = 0; + PHYSFS_Io *io = NULL; + + BAIL_IF_MACRO(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + io = __PHYSFS_createMemoryIo(buf, len, del); + BAIL_IF_MACRO(!io, ERRPASS, 0); + retval = doMount(io, fname, mountPoint, appendToPath); + if (!retval) + { + /* docs say not to call (del) in case of failure, so cheat. */ + MemoryIoInfo *info = (MemoryIoInfo *) io->opaque; + info->destruct = NULL; + io->destroy(io); + } /* if */ + + return retval; +} /* PHYSFS_mountMemory */ + + +int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, + const char *mountPoint, int appendToPath) +{ + int retval = 0; + PHYSFS_Io *io = NULL; + + BAIL_IF_MACRO(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + io = __PHYSFS_createHandleIo(file); + BAIL_IF_MACRO(!io, ERRPASS, 0); + retval = doMount(io, fname, mountPoint, appendToPath); + if (!retval) + { + /* docs say not to destruct in case of failure, so cheat. */ + io->opaque = NULL; + io->destroy(io); + } /* if */ + + return retval; +} /* PHYSFS_mountHandle */ + + +int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath) +{ + BAIL_IF_MACRO(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0); + return doMount(NULL, newDir, mountPoint, appendToPath); +} /* PHYSFS_mount */ + + +int PHYSFS_addToSearchPath(const char *newDir, int appendToPath) +{ + return doMount(NULL, newDir, NULL, appendToPath); +} /* PHYSFS_addToSearchPath */ + + +int PHYSFS_removeFromSearchPath(const char *oldDir) +{ + return PHYSFS_unmount(oldDir); +} /* PHYSFS_removeFromSearchPath */ + + +int PHYSFS_unmount(const char *oldDir) +{ + DirHandle *i; + DirHandle *prev = NULL; + DirHandle *next = NULL; + + BAIL_IF_MACRO(oldDir == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; i != NULL; i = i->next) + { + if (strcmp(i->dirName, oldDir) == 0) + { + next = i->next; + BAIL_IF_MACRO_MUTEX(!freeDirHandle(i, openReadList), ERRPASS, + stateLock, 0); + + if (prev == NULL) + searchPath = next; + else + prev->next = next; + + BAIL_MACRO_MUTEX(ERRPASS, stateLock, 1); + } /* if */ + prev = i; + } /* for */ + + BAIL_MACRO_MUTEX(PHYSFS_ERR_NOT_MOUNTED, stateLock, 0); +} /* PHYSFS_unmount */ + + +char **PHYSFS_getSearchPath(void) +{ + return doEnumStringList(PHYSFS_getSearchPathCallback); +} /* PHYSFS_getSearchPath */ + + +const char *PHYSFS_getMountPoint(const char *dir) +{ + DirHandle *i; + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; i != NULL; i = i->next) + { + if (strcmp(i->dirName, dir) == 0) + { + const char *retval = ((i->mountPoint) ? i->mountPoint : "/"); + __PHYSFS_platformReleaseMutex(stateLock); + return retval; + } /* if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + + BAIL_MACRO(PHYSFS_ERR_NOT_MOUNTED, NULL); +} /* PHYSFS_getMountPoint */ + + +void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data) +{ + DirHandle *i; + + __PHYSFS_platformGrabMutex(stateLock); + + for (i = searchPath; i != NULL; i = i->next) + callback(data, i->dirName); + + __PHYSFS_platformReleaseMutex(stateLock); +} /* PHYSFS_getSearchPathCallback */ + + +/* Split out to avoid stack allocation in a loop. */ +static void setSaneCfgAddPath(const char *i, const size_t l, const char *dirsep, + int archivesFirst) +{ + const char *d = PHYSFS_getRealDir(i); + const size_t allocsize = strlen(d) + strlen(dirsep) + l + 1; + char *str = (char *) __PHYSFS_smallAlloc(allocsize); + if (str != NULL) + { + sprintf(str, "%s%s%s", d, dirsep, i); + PHYSFS_mount(str, NULL, archivesFirst == 0); + __PHYSFS_smallFree(str); + } /* if */ +} /* setSaneCfgAddPath */ + + +int PHYSFS_setSaneConfig(const char *organization, const char *appName, + const char *archiveExt, int includeCdRoms, + int archivesFirst) +{ + const char *dirsep = PHYSFS_getDirSeparator(); + const char *basedir; + const char *prefdir; + + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); + + prefdir = PHYSFS_getPrefDir(organization, appName); + BAIL_IF_MACRO(!prefdir, ERRPASS, 0); + + basedir = PHYSFS_getBaseDir(); + BAIL_IF_MACRO(!basedir, ERRPASS, 0); + + BAIL_IF_MACRO(!PHYSFS_setWriteDir(prefdir), PHYSFS_ERR_NO_WRITE_DIR, 0); + + /* Put write dir first in search path... */ + PHYSFS_mount(prefdir, NULL, 0); + + /* Put base path on search path... */ + PHYSFS_mount(basedir, NULL, 1); + + /* handle CD-ROMs... */ + if (includeCdRoms) + { + char **cds = PHYSFS_getCdRomDirs(); + char **i; + for (i = cds; *i != NULL; i++) + PHYSFS_mount(*i, NULL, 1); + PHYSFS_freeList(cds); + } /* if */ + + /* Root out archives, and add them to search path... */ + if (archiveExt != NULL) + { + char **rc = PHYSFS_enumerateFiles("/"); + char **i; + size_t extlen = strlen(archiveExt); + char *ext; + + for (i = rc; *i != NULL; i++) + { + size_t l = strlen(*i); + if ((l > extlen) && ((*i)[l - extlen - 1] == '.')) + { + ext = (*i) + (l - extlen); + if (__PHYSFS_stricmpASCII(ext, archiveExt) == 0) + setSaneCfgAddPath(*i, l, dirsep, archivesFirst); + } /* if */ + } /* for */ + + PHYSFS_freeList(rc); + } /* if */ + + return 1; +} /* PHYSFS_setSaneConfig */ + + +void PHYSFS_permitSymbolicLinks(int allow) +{ + allowSymLinks = allow; +} /* PHYSFS_permitSymbolicLinks */ + + +int PHYSFS_symbolicLinksPermitted(void) +{ + return allowSymLinks; +} /* PHYSFS_symbolicLinksPermitted */ + + +/* + * Verify that (fname) (in platform-independent notation), in relation + * to (h) is secure. That means that each element of fname is checked + * for symlinks (if they aren't permitted). This also allows for quick + * rejection of files that exist outside an archive's mountpoint. + * + * With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs + * at a time), you should always pass zero for "allowMissing" for efficiency. + * + * (fname) must point to an output from sanitizePlatformIndependentPath(), + * since it will make sure that path names are in the right format for + * passing certain checks. It will also do checks for "insecure" pathnames + * like ".." which should be done once instead of once per archive. This also + * gives us license to treat (fname) as scratch space in this function. + * + * Returns non-zero if string is safe, zero if there's a security issue. + * PHYSFS_getLastError() will specify what was wrong. (*fname) will be + * updated to point past any mount point elements so it is prepared to + * be used with the archiver directly. + */ +static int verifyPath(DirHandle *h, char **_fname, int allowMissing) +{ + char *fname = *_fname; + int retval = 1; + char *start; + char *end; + + if (*fname == '\0') /* quick rejection. */ + return 1; + + /* !!! FIXME: This codeblock sucks. */ + if (h->mountPoint != NULL) /* NULL mountpoint means "/". */ + { + size_t mntpntlen = strlen(h->mountPoint); + size_t len = strlen(fname); + assert(mntpntlen > 1); /* root mount points should be NULL. */ + /* not under the mountpoint, so skip this archive. */ + BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0); + /* !!! FIXME: Case insensitive? */ + retval = strncmp(h->mountPoint, fname, mntpntlen-1); + BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0); + if (len > mntpntlen-1) /* corner case... */ + BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0); + fname += mntpntlen-1; /* move to start of actual archive path. */ + if (*fname == '/') + fname++; + *_fname = fname; /* skip mountpoint for later use. */ + retval = 1; /* may be reset, below. */ + } /* if */ + + start = fname; + if (!allowSymLinks) + { + while (1) + { + PHYSFS_Stat statbuf; + int rc = 0; + end = strchr(start, '/'); + + if (end != NULL) *end = '\0'; + rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf); + if (rc) + rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK); + if (end != NULL) *end = '/'; + + /* insecure path (has a disallowed symlink in it)? */ + BAIL_IF_MACRO(rc, PHYSFS_ERR_SYMLINK_FORBIDDEN, 0); + + /* break out early if path element is missing. */ + if (!retval) + { + /* + * We need to clear it if it's the last element of the path, + * since this might be a non-existant file we're opening + * for writing... + */ + if ((end == NULL) || (allowMissing)) + retval = 1; + break; + } /* if */ + + if (end == NULL) + break; + + start = end + 1; + } /* while */ + } /* if */ + + return retval; +} /* verifyPath */ + + +static int doMkdir(const char *_dname, char *dname) +{ + DirHandle *h; + char *start; + char *end; + int retval = 0; + int exists = 1; /* force existance check on first path element. */ + + BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_dname, dname), ERRPASS, 0); + + __PHYSFS_platformGrabMutex(stateLock); + BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + h = writeDir; + BAIL_IF_MACRO_MUTEX(!verifyPath(h, &dname, 1), ERRPASS, stateLock, 0); + + start = dname; + while (1) + { + end = strchr(start, '/'); + if (end != NULL) + *end = '\0'; + + /* only check for existance if all parent dirs existed, too... */ + if (exists) + { + PHYSFS_Stat statbuf; + const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf); + retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY)); + } /* if */ + + if (!exists) + retval = h->funcs->mkdir(h->opaque, dname); + + if (!retval) + break; + + if (end == NULL) + break; + + *end = '/'; + start = end + 1; + } /* while */ + + __PHYSFS_platformReleaseMutex(stateLock); + return retval; +} /* doMkdir */ + + +int PHYSFS_mkdir(const char *_dname) +{ + int retval = 0; + char *dname; + size_t len; + + BAIL_IF_MACRO(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0); + len = strlen(_dname) + 1; + dname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + retval = doMkdir(_dname, dname); + __PHYSFS_smallFree(dname); + return retval; +} /* PHYSFS_mkdir */ + + +static int doDelete(const char *_fname, char *fname) +{ + int retval; + DirHandle *h; + BAIL_IF_MACRO(!sanitizePlatformIndependentPath(_fname, fname), ERRPASS, 0); + + __PHYSFS_platformGrabMutex(stateLock); + + BAIL_IF_MACRO_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + h = writeDir; + BAIL_IF_MACRO_MUTEX(!verifyPath(h, &fname, 0), ERRPASS, stateLock, 0); + retval = h->funcs->remove(h->opaque, fname); + + __PHYSFS_platformReleaseMutex(stateLock); + return retval; +} /* doDelete */ + + +int PHYSFS_delete(const char *_fname) +{ + int retval; + char *fname; + size_t len; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + retval = doDelete(_fname, fname); + __PHYSFS_smallFree(fname); + return retval; +} /* PHYSFS_delete */ + + +const char *PHYSFS_getRealDir(const char *_fname) +{ + const char *retval = NULL; + char *fname = NULL; + size_t len; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL); + len = strlen(_fname) + 1; + fname = __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + if (sanitizePlatformIndependentPath(_fname, fname)) + { + DirHandle *i; + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; i != NULL; i = i->next) + { + char *arcfname = fname; + if (partOfMountPoint(i, arcfname)) + { + retval = i->dirName; + break; + } /* if */ + else if (verifyPath(i, &arcfname, 0)) + { + PHYSFS_Stat statbuf; + int exists = 0; + if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf)) + { + if (exists) + retval = i->dirName; + break; + } /* if */ + } /* if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + } /* if */ + + __PHYSFS_smallFree(fname); + return retval; +} /* PHYSFS_getRealDir */ + + +static int locateInStringList(const char *str, + char **list, + PHYSFS_uint32 *pos) +{ + PHYSFS_uint32 len = *pos; + PHYSFS_uint32 half_len; + PHYSFS_uint32 lo = 0; + PHYSFS_uint32 middle; + int cmp; + + while (len > 0) + { + half_len = len >> 1; + middle = lo + half_len; + cmp = strcmp(list[middle], str); + + if (cmp == 0) /* it's in the list already. */ + return 1; + else if (cmp > 0) + len = half_len; + else + { + lo = middle + 1; + len -= half_len + 1; + } /* else */ + } /* while */ + + *pos = lo; + return 0; +} /* locateInStringList */ + + +static void enumFilesCallback(void *data, const char *origdir, const char *str) +{ + PHYSFS_uint32 pos; + void *ptr; + char *newstr; + EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data; + + /* + * See if file is in the list already, and if not, insert it in there + * alphabetically... + */ + pos = pecd->size; + if (locateInStringList(str, pecd->list, &pos)) + return; /* already in the list. */ + + ptr = allocator.Realloc(pecd->list, (pecd->size + 2) * sizeof (char *)); + newstr = (char *) allocator.Malloc(strlen(str) + 1); + if (ptr != NULL) + pecd->list = (char **) ptr; + + if ((ptr == NULL) || (newstr == NULL)) + return; /* better luck next time. */ + + strcpy(newstr, str); + + if (pos != pecd->size) + { + memmove(&pecd->list[pos+1], &pecd->list[pos], + sizeof (char *) * ((pecd->size) - pos)); + } /* if */ + + pecd->list[pos] = newstr; + pecd->size++; +} /* enumFilesCallback */ + + +char **PHYSFS_enumerateFiles(const char *path) +{ + EnumStringListCallbackData ecd; + memset(&ecd, '\0', sizeof (ecd)); + ecd.list = (char **) allocator.Malloc(sizeof (char *)); + BAIL_IF_MACRO(!ecd.list, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd); + ecd.list[ecd.size] = NULL; + return ecd.list; +} /* PHYSFS_enumerateFiles */ + + +/* + * Broke out to seperate function so we can use stack allocation gratuitously. + */ +static void enumerateFromMountPoint(DirHandle *i, const char *arcfname, + PHYSFS_EnumFilesCallback callback, + const char *_fname, void *data) +{ + const size_t len = strlen(arcfname); + char *ptr = NULL; + char *end = NULL; + const size_t slen = strlen(i->mountPoint) + 1; + char *mountPoint = (char *) __PHYSFS_smallAlloc(slen); + + if (mountPoint == NULL) + return; /* oh well. */ + + strcpy(mountPoint, i->mountPoint); + ptr = mountPoint + ((len) ? len + 1 : 0); + end = strchr(ptr, '/'); + assert(end); /* should always find a terminating '/'. */ + *end = '\0'; + callback(data, _fname, ptr); + __PHYSFS_smallFree(mountPoint); +} /* enumerateFromMountPoint */ + + +/* !!! FIXME: this should report error conditions. */ +void PHYSFS_enumerateFilesCallback(const char *_fname, + PHYSFS_EnumFilesCallback callback, + void *data) +{ + size_t len; + char *fname; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/; + BAIL_IF_MACRO(!callback, PHYSFS_ERR_INVALID_ARGUMENT, ) /*0*/; + + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/; + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + DirHandle *i; + int noSyms; + + __PHYSFS_platformGrabMutex(stateLock); + noSyms = !allowSymLinks; + for (i = searchPath; i != NULL; i = i->next) + { + char *arcfname = fname; + if (partOfMountPoint(i, arcfname)) + enumerateFromMountPoint(i, arcfname, callback, _fname, data); + + else if (verifyPath(i, &arcfname, 0)) + { + i->funcs->enumerateFiles(i->opaque, arcfname, noSyms, + callback, _fname, data); + } /* else if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + } /* if */ + + __PHYSFS_smallFree(fname); +} /* PHYSFS_enumerateFilesCallback */ + + +int PHYSFS_exists(const char *fname) +{ + return (PHYSFS_getRealDir(fname) != NULL); +} /* PHYSFS_exists */ + + +PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname) +{ + PHYSFS_Stat statbuf; + BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, -1); + return statbuf.modtime; +} /* PHYSFS_getLastModTime */ + + +int PHYSFS_isDirectory(const char *fname) +{ + PHYSFS_Stat statbuf; + BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0); + return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY); +} /* PHYSFS_isDirectory */ + + +int PHYSFS_isSymbolicLink(const char *fname) +{ + PHYSFS_Stat statbuf; + BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), ERRPASS, 0); + return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK); +} /* PHYSFS_isSymbolicLink */ + + +static PHYSFS_File *doOpenWrite(const char *_fname, int appending) +{ + FileHandle *fh = NULL; + size_t len; + char *fname; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + PHYSFS_Io *io = NULL; + DirHandle *h = NULL; + const PHYSFS_Archiver *f; + + __PHYSFS_platformGrabMutex(stateLock); + + GOTO_IF_MACRO(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd); + + h = writeDir; + GOTO_IF_MACRO(!verifyPath(h, &fname, 0), ERRPASS, doOpenWriteEnd); + + f = h->funcs; + if (appending) + io = f->openAppend(h->opaque, fname); + else + io = f->openWrite(h->opaque, fname); + + GOTO_IF_MACRO(!io, ERRPASS, doOpenWriteEnd); + + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd); + } /* if */ + else + { + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->dirHandle = h; + fh->next = openWriteList; + openWriteList = fh; + } /* else */ + + doOpenWriteEnd: + __PHYSFS_platformReleaseMutex(stateLock); + } /* if */ + + __PHYSFS_smallFree(fname); + return ((PHYSFS_File *) fh); +} /* doOpenWrite */ + + +PHYSFS_File *PHYSFS_openWrite(const char *filename) +{ + return doOpenWrite(filename, 0); +} /* PHYSFS_openWrite */ + + +PHYSFS_File *PHYSFS_openAppend(const char *filename) +{ + return doOpenWrite(filename, 1); +} /* PHYSFS_openAppend */ + + +PHYSFS_File *PHYSFS_openRead(const char *_fname) +{ + FileHandle *fh = NULL; + char *fname; + size_t len; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + int fileExists = 0; + DirHandle *i = NULL; + PHYSFS_Io *io = NULL; + + __PHYSFS_platformGrabMutex(stateLock); + + GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd); + + for (i = searchPath; (i != NULL) && (!fileExists); i = i->next) + { + char *arcfname = fname; + if (verifyPath(i, &arcfname, 0)) + { + io = i->funcs->openRead(i->opaque, arcfname, &fileExists); + if (io) + break; + } /* if */ + } /* for */ + + GOTO_IF_MACRO(!io, ERRPASS, openReadEnd); + + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + GOTO_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd); + } /* if */ + + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->forReading = 1; + fh->dirHandle = i; + fh->next = openReadList; + openReadList = fh; + + openReadEnd: + __PHYSFS_platformReleaseMutex(stateLock); + } /* if */ + + __PHYSFS_smallFree(fname); + return ((PHYSFS_File *) fh); +} /* PHYSFS_openRead */ + + +static int closeHandleInOpenList(FileHandle **list, FileHandle *handle) +{ + FileHandle *prev = NULL; + FileHandle *i; + int rc = 1; + + for (i = *list; i != NULL; i = i->next) + { + if (i == handle) /* handle is in this list? */ + { + PHYSFS_Io *io = handle->io; + PHYSFS_uint8 *tmp = handle->buffer; + rc = PHYSFS_flush((PHYSFS_File *) handle); + if (!rc) + return -1; + io->destroy(io); + + if (tmp != NULL) /* free any associated buffer. */ + allocator.Free(tmp); + + if (prev == NULL) + *list = handle->next; + else + prev->next = handle->next; + + allocator.Free(handle); + return 1; + } /* if */ + prev = i; + } /* for */ + + return 0; +} /* closeHandleInOpenList */ + + +int PHYSFS_close(PHYSFS_File *_handle) +{ + FileHandle *handle = (FileHandle *) _handle; + int rc; + + __PHYSFS_platformGrabMutex(stateLock); + + /* -1 == close failure. 0 == not found. 1 == success. */ + rc = closeHandleInOpenList(&openReadList, handle); + BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0); + if (!rc) + { + rc = closeHandleInOpenList(&openWriteList, handle); + BAIL_IF_MACRO_MUTEX(rc == -1, ERRPASS, stateLock, 0); + } /* if */ + + __PHYSFS_platformReleaseMutex(stateLock); + BAIL_IF_MACRO(!rc, PHYSFS_ERR_INVALID_ARGUMENT, 0); + return 1; +} /* PHYSFS_close */ + + +static PHYSFS_sint64 doBufferedRead(FileHandle *fh, void *buffer, + PHYSFS_uint64 len) +{ + PHYSFS_Io *io = NULL; + PHYSFS_sint64 retval = 0; + PHYSFS_uint32 buffered = 0; + PHYSFS_sint64 rc = 0; + + if (len == 0) + return 0; + + buffered = fh->buffill - fh->bufpos; + if (buffered >= len) /* totally in the buffer, just copy and return! */ + { + memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len); + fh->bufpos += (PHYSFS_uint32) len; + return (PHYSFS_sint64) len; + } /* else if */ + + if (buffered > 0) /* partially in the buffer... */ + { + memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered); + buffer = ((PHYSFS_uint8 *) buffer) + buffered; + len -= buffered; + retval = buffered; + fh->buffill = fh->bufpos = 0; + } /* if */ + + /* if you got here, the buffer is drained and we still need bytes. */ + assert(len > 0); + + io = fh->io; + if (len >= fh->bufsize) /* need more than the buffer takes. */ + { + /* leave buffer empty, go right to output instead. */ + rc = io->read(io, buffer, len); + if (rc < 0) + return ((retval == 0) ? rc : retval); + return retval + rc; + } /* if */ + + /* need less than buffer can take. Fill buffer. */ + rc = io->read(io, fh->buffer, fh->bufsize); + if (rc < 0) + return ((retval == 0) ? rc : retval); + + assert(fh->bufpos == 0); + fh->buffill = (PHYSFS_uint32) rc; + rc = doBufferedRead(fh, buffer, len); /* go from the start, again. */ + if (rc < 0) + return ((retval == 0) ? rc : retval); + + return retval + rc; +} /* doBufferedRead */ + + +PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, + PHYSFS_uint32 size, PHYSFS_uint32 count) +{ + const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count); + const PHYSFS_sint64 retval = PHYSFS_readBytes(handle, buffer, len); + return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) ); +} /* PHYSFS_read */ + + +PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, + PHYSFS_uint64 len) +{ + FileHandle *fh = (FileHandle *) handle; + +#ifdef PHYSFS_NO_64BIT_SUPPORT + const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF); +#else + const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF); +#endif + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1); + BAIL_IF_MACRO(!fh->forReading, PHYSFS_ERR_OPEN_FOR_WRITING, -1); + BAIL_IF_MACRO(len == 0, ERRPASS, 0); + if (fh->buffer) + return doBufferedRead(fh, buffer, len); + + return fh->io->read(fh->io, buffer, len); +} /* PHYSFS_readBytes */ + + +static PHYSFS_sint64 doBufferedWrite(PHYSFS_File *handle, const void *buffer, + PHYSFS_uint64 len) +{ + FileHandle *fh = (FileHandle *) handle; + + /* whole thing fits in the buffer? */ + if ( (((PHYSFS_uint64) fh->buffill) + len) < fh->bufsize ) + { + memcpy(fh->buffer + fh->buffill, buffer, (size_t) len); + fh->buffill += (PHYSFS_uint32) len; + return (PHYSFS_sint64) len; + } /* if */ + + /* would overflow buffer. Flush and then write the new objects, too. */ + BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, -1); + return fh->io->write(fh->io, buffer, len); +} /* doBufferedWrite */ + + +PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, + PHYSFS_uint32 size, PHYSFS_uint32 count) +{ + const PHYSFS_uint64 len = ((PHYSFS_uint64) size) * ((PHYSFS_uint64) count); + const PHYSFS_sint64 retval = PHYSFS_writeBytes(handle, buffer, len); + return ( (retval <= 0) ? retval : (retval / ((PHYSFS_sint64) size)) ); +} /* PHYSFS_write */ + + +PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer, + PHYSFS_uint64 len) +{ + FileHandle *fh = (FileHandle *) handle; + +#ifdef PHYSFS_NO_64BIT_SUPPORT + const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFF); +#else + const PHYSFS_uint64 maxlen = __PHYSFS_UI64(0x7FFFFFFFFFFFFFFF); +#endif + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + BAIL_IF_MACRO(len > maxlen, PHYSFS_ERR_INVALID_ARGUMENT, -1); + BAIL_IF_MACRO(fh->forReading, PHYSFS_ERR_OPEN_FOR_READING, -1); + BAIL_IF_MACRO(len == 0, ERRPASS, 0); + if (fh->buffer) + return doBufferedWrite(handle, buffer, len); + + return fh->io->write(fh->io, buffer, len); +} /* PHYSFS_write */ + + +int PHYSFS_eof(PHYSFS_File *handle) +{ + FileHandle *fh = (FileHandle *) handle; + + if (!fh->forReading) /* never EOF on files opened for write/append. */ + return 0; + + /* can't be eof if buffer isn't empty */ + if (fh->bufpos == fh->buffill) + { + /* check the Io. */ + PHYSFS_Io *io = fh->io; + const PHYSFS_sint64 pos = io->tell(io); + const PHYSFS_sint64 len = io->length(io); + if ((pos < 0) || (len < 0)) + return 0; /* beats me. */ + return (pos >= len); + } /* if */ + + return 0; +} /* PHYSFS_eof */ + + +PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle) +{ + FileHandle *fh = (FileHandle *) handle; + const PHYSFS_sint64 pos = fh->io->tell(fh->io); + const PHYSFS_sint64 retval = fh->forReading ? + (pos - fh->buffill) + fh->bufpos : + (pos + fh->buffill); + return retval; +} /* PHYSFS_tell */ + + +int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos) +{ + FileHandle *fh = (FileHandle *) handle; + BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0); + + if (fh->buffer && fh->forReading) + { + /* avoid throwing away our precious buffer if seeking within it. */ + PHYSFS_sint64 offset = pos - PHYSFS_tell(handle); + if ( /* seeking within the already-buffered range? */ + ((offset >= 0) && (offset <= fh->buffill - fh->bufpos)) /* fwd */ + || ((offset < 0) && (-offset <= fh->bufpos)) /* backward */ ) + { + fh->bufpos += (PHYSFS_uint32) offset; + return 1; /* successful seek */ + } /* if */ + } /* if */ + + /* we have to fall back to a 'raw' seek. */ + fh->buffill = fh->bufpos = 0; + return fh->io->seek(fh->io, pos); +} /* PHYSFS_seek */ + + +PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle) +{ + PHYSFS_Io *io = ((FileHandle *) handle)->io; + return io->length(io); +} /* PHYSFS_filelength */ + + +int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 _bufsize) +{ + FileHandle *fh = (FileHandle *) handle; + PHYSFS_uint32 bufsize; + + /* !!! FIXME: actually, why use 32 bits here? */ + /*BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, "buffer must fit in 32-bits", 0);*/ + BAIL_IF_MACRO(_bufsize > 0xFFFFFFFF, PHYSFS_ERR_INVALID_ARGUMENT, 0); + bufsize = (PHYSFS_uint32) _bufsize; + + BAIL_IF_MACRO(!PHYSFS_flush(handle), ERRPASS, 0); + + /* + * For reads, we need to move the file pointer to where it would be + * if we weren't buffering, so that the next read will get the + * right chunk of stuff from the file. PHYSFS_flush() handles writes. + */ + if ((fh->forReading) && (fh->buffill != fh->bufpos)) + { + PHYSFS_uint64 pos; + const PHYSFS_sint64 curpos = fh->io->tell(fh->io); + BAIL_IF_MACRO(curpos == -1, ERRPASS, 0); + pos = ((curpos - fh->buffill) + fh->bufpos); + BAIL_IF_MACRO(!fh->io->seek(fh->io, pos), ERRPASS, 0); + } /* if */ + + if (bufsize == 0) /* delete existing buffer. */ + { + if (fh->buffer) + { + allocator.Free(fh->buffer); + fh->buffer = NULL; + } /* if */ + } /* if */ + + else + { + PHYSFS_uint8 *newbuf; + newbuf = (PHYSFS_uint8 *) allocator.Realloc(fh->buffer, bufsize); + BAIL_IF_MACRO(!newbuf, PHYSFS_ERR_OUT_OF_MEMORY, 0); + fh->buffer = newbuf; + } /* else */ + + fh->bufsize = bufsize; + fh->buffill = fh->bufpos = 0; + return 1; +} /* PHYSFS_setBuffer */ + + +int PHYSFS_flush(PHYSFS_File *handle) +{ + FileHandle *fh = (FileHandle *) handle; + PHYSFS_Io *io; + PHYSFS_sint64 rc; + + if ((fh->forReading) || (fh->bufpos == fh->buffill)) + return 1; /* open for read or buffer empty are successful no-ops. */ + + /* dump buffer to disk. */ + io = fh->io; + rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos); + BAIL_IF_MACRO(rc <= 0, ERRPASS, 0); + fh->bufpos = fh->buffill = 0; + return io->flush(io); +} /* PHYSFS_flush */ + + +int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) +{ + int retval = 0; + char *fname; + size_t len; + + BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1); + BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1); + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1); + + /* set some sane defaults... */ + stat->filesize = -1; + stat->modtime = -1; + stat->createtime = -1; + stat->accesstime = -1; + stat->filetype = PHYSFS_FILETYPE_OTHER; + stat->readonly = 1; /* !!! FIXME */ + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + if (*fname == '\0') + { + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + stat->readonly = !writeDir; /* Writeable if we have a writeDir */ + retval = 1; + } /* if */ + else + { + DirHandle *i; + int exists = 0; + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; ((i != NULL) && (!exists)); i = i->next) + { + char *arcfname = fname; + exists = partOfMountPoint(i, arcfname); + if (exists) + { + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + stat->readonly = 1; /* !!! FIXME */ + retval = 1; + } /* if */ + else if (verifyPath(i, &arcfname, 0)) + { + /* !!! FIXME: this test is wrong and should be elsewhere. */ + stat->readonly = !(writeDir && + (strcmp(writeDir->dirName, i->dirName) == 0)); + retval = i->funcs->stat(i->opaque, arcfname, &exists, stat); + } /* else if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + } /* else */ + } /* if */ + + __PHYSFS_smallFree(fname); + return retval; +} /* PHYSFS_stat */ + + +int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len) +{ + return (io->read(io, buf, len) == len); +} /* __PHYSFS_readAll */ + + +void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len) +{ + void *useHeap = ((ptr == NULL) ? ((void *) 1) : ((void *) 0)); + if (useHeap) /* too large for stack allocation or alloca() failed. */ + ptr = allocator.Malloc(len+sizeof (void *)); + + if (ptr != NULL) + { + void **retval = (void **) ptr; + /*printf("%s alloc'd (%d) bytes at (%p).\n", + useHeap ? "heap" : "stack", (int) len, ptr);*/ + *retval = useHeap; + return retval + 1; + } /* if */ + + return NULL; /* allocation failed. */ +} /* __PHYSFS_initSmallAlloc */ + + +void __PHYSFS_smallFree(void *ptr) +{ + if (ptr != NULL) + { + void **block = ((void **) ptr) - 1; + const int useHeap = (*block != 0); + if (useHeap) + allocator.Free(block); + /*printf("%s free'd (%p).\n", useHeap ? "heap" : "stack", block);*/ + } /* if */ +} /* __PHYSFS_smallFree */ + + +int PHYSFS_setAllocator(const PHYSFS_Allocator *a) +{ + BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0); + externalAllocator = (a != NULL); + if (externalAllocator) + memcpy(&allocator, a, sizeof (PHYSFS_Allocator)); + + return 1; +} /* PHYSFS_setAllocator */ + + +const PHYSFS_Allocator *PHYSFS_getAllocator(void) +{ + BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL); + return &allocator; +} /* PHYSFS_getAllocator */ + + +static void *mallocAllocatorMalloc(PHYSFS_uint64 s) +{ + if (!__PHYSFS_ui64FitsAddressSpace(s)) + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + #undef malloc + return malloc((size_t) s); +} /* mallocAllocatorMalloc */ + + +static void *mallocAllocatorRealloc(void *ptr, PHYSFS_uint64 s) +{ + if (!__PHYSFS_ui64FitsAddressSpace(s)) + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + #undef realloc + return realloc(ptr, (size_t) s); +} /* mallocAllocatorRealloc */ + + +static void mallocAllocatorFree(void *ptr) +{ + #undef free + free(ptr); +} /* mallocAllocatorFree */ + + +static void setDefaultAllocator(void) +{ + assert(!externalAllocator); + if (!__PHYSFS_platformSetDefaultAllocator(&allocator)) + { + allocator.Init = NULL; + allocator.Deinit = NULL; + allocator.Malloc = mallocAllocatorMalloc; + allocator.Realloc = mallocAllocatorRealloc; + allocator.Free = mallocAllocatorFree; + } /* if */ +} /* setDefaultAllocator */ + +/* end of physfs.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,3324 @@ +/** + * \file physfs.h + * + * Main header file for PhysicsFS. + */ + +/** + * \mainpage PhysicsFS + * + * The latest version of PhysicsFS can be found at: + * http://icculus.org/physfs/ + * + * PhysicsFS; a portable, flexible file i/o abstraction. + * + * This API gives you access to a system file system in ways superior to the + * stdio or system i/o calls. The brief benefits: + * + * - It's portable. + * - It's safe. No file access is permitted outside the specified dirs. + * - It's flexible. Archives (.ZIP files) can be used transparently as + * directory structures. + * + * This system is largely inspired by Quake 3's PK3 files and the related + * fs_* cvars. If you've ever tinkered with these, then this API will be + * familiar to you. + * + * With PhysicsFS, you have a single writing directory and multiple + * directories (the "search path") for reading. You can think of this as a + * filesystem within a filesystem. If (on Windows) you were to set the + * writing directory to "C:\MyGame\MyWritingDirectory", then no PHYSFS calls + * could touch anything above this directory, including the "C:\MyGame" and + * "C:\" directories. This prevents an application's internal scripting + * language from piddling over c:\\config.sys, for example. If you'd rather + * give PHYSFS full access to the system's REAL file system, set the writing + * dir to "C:\", but that's generally A Bad Thing for several reasons. + * + * Drive letters are hidden in PhysicsFS once you set up your initial paths. + * The search path creates a single, hierarchical directory structure. + * Not only does this lend itself well to general abstraction with archives, + * it also gives better support to operating systems like MacOS and Unix. + * Generally speaking, you shouldn't ever hardcode a drive letter; not only + * does this hurt portability to non-Microsoft OSes, but it limits your win32 + * users to a single drive, too. Use the PhysicsFS abstraction functions and + * allow user-defined configuration options, too. When opening a file, you + * specify it like it was on a Unix filesystem: if you want to write to + * "C:\MyGame\MyConfigFiles\game.cfg", then you might set the write dir to + * "C:\MyGame" and then open "MyConfigFiles/game.cfg". This gives an + * abstraction across all platforms. Specifying a file in this way is termed + * "platform-independent notation" in this documentation. Specifying a + * a filename in a form such as "C:\mydir\myfile" or + * "MacOS hard drive:My Directory:My File" is termed "platform-dependent + * notation". The only time you use platform-dependent notation is when + * setting up your write directory and search path; after that, all file + * access into those directories are done with platform-independent notation. + * + * All files opened for writing are opened in relation to the write directory, + * which is the root of the writable filesystem. When opening a file for + * reading, PhysicsFS goes through the search path. This is NOT the + * same thing as the PATH environment variable. An application using + * PhysicsFS specifies directories to be searched which may be actual + * directories, or archive files that contain files and subdirectories of + * their own. See the end of these docs for currently supported archive + * formats. + * + * Once the search path is defined, you may open files for reading. If you've + * got the following search path defined (to use a win32 example again): + * + * - C:\\mygame + * - C:\\mygame\\myuserfiles + * - D:\\mygamescdromdatafiles + * - C:\\mygame\\installeddatafiles.zip + * + * Then a call to PHYSFS_openRead("textfiles/myfile.txt") (note the directory + * separator, lack of drive letter, and lack of dir separator at the start of + * the string; this is platform-independent notation) will check for + * C:\\mygame\\textfiles\\myfile.txt, then + * C:\\mygame\\myuserfiles\\textfiles\\myfile.txt, then + * D:\\mygamescdromdatafiles\\textfiles\\myfile.txt, then, finally, for + * textfiles\\myfile.txt inside of C:\\mygame\\installeddatafiles.zip. + * Remember that most archive types and platform filesystems store their + * filenames in a case-sensitive manner, so you should be careful to specify + * it correctly. + * + * Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir + * elements. Not only are these meaningless on MacOS Classic and/or Unix, + * they are a security hole. Also, symbolic links (which can be found in + * some archive types and directly in the filesystem on Unix platforms) are + * NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to + * your own discretion, as following a symlink can allow for access outside + * the write dir and search paths. For portability, there is no mechanism for + * creating new symlinks in PhysicsFS. + * + * The write dir is not included in the search path unless you specifically + * add it. While you CAN change the write dir as many times as you like, + * you should probably set it once and stick to it. Remember that your + * program will not have permission to write in every directory on Unix and + * NT systems. + * + * All files are opened in binary mode; there is no endline conversion for + * textfiles. Other than that, PhysicsFS has some convenience functions for + * platform-independence. There is a function to tell you the current + * platform's dir separator ("\\" on windows, "/" on Unix, ":" on MacOS), + * which is needed only to set up your search/write paths. There is a + * function to tell you what CD-ROM drives contain accessible discs, and a + * function to recommend a good search path, etc. + * + * A recommended order for the search path is the write dir, then the base dir, + * then the cdrom dir, then any archives discovered. Quake 3 does something + * like this, but moves the archives to the start of the search path. Build + * Engine games, like Duke Nukem 3D and Blood, place the archives last, and + * use the base dir for both searching and writing. There is a helper + * function (PHYSFS_setSaneConfig()) that puts together a basic configuration + * for you, based on a few parameters. Also see the comments on + * PHYSFS_getBaseDir(), and PHYSFS_getPrefDir() for info on what those + * are and how they can help you determine an optimal search path. + * + * PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points + * in the search path. If a zipfile contains "maps/level.map" and you mount + * that archive at "mods/mymod", then you would have to open + * "mods/mymod/maps/level.map" to access the file, even though "mods/mymod" + * isn't actually specified in the .zip file. Unlike the Unix mentality of + * mounting a filesystem, "mods/mymod" doesn't actually have to exist when + * mounting the zipfile. It's a "virtual" directory. The mounting mechanism + * allows the developer to seperate archives in the tree and avoid trampling + * over files when added new archives, such as including mod support in a + * game...keeping external content on a tight leash in this manner can be of + * utmost importance to some applications. + * + * PhysicsFS is mostly thread safe. The error messages returned by + * PHYSFS_getLastError() are unique by thread, and library-state-setting + * functions are mutex'd. For efficiency, individual file accesses are + * not locked, so you can not safely read/write/seek/close/etc the same + * file from two threads at the same time. Other race conditions are bugs + * that should be reported/patched. + * + * While you CAN use stdio/syscall file access in a program that has PHYSFS_* + * calls, doing so is not recommended, and you can not use system + * filehandles with PhysicsFS and vice versa. + * + * Note that archives need not be named as such: if you have a ZIP file and + * rename it with a .PKG extension, the file will still be recognized as a + * ZIP archive by PhysicsFS; the file's contents are used to determine its + * type where possible. + * + * Currently supported archive types: + * - .ZIP (pkZip/WinZip/Info-ZIP compatible) + * - .7Z (7zip archives) + * - .ISO (ISO9660 files, CD-ROM images) + * - .GRP (Build Engine groupfile archives) + * - .PAK (Quake I/II archive format) + * - .HOG (Descent I/II HOG file archives) + * - .MVL (Descent II movielib archives) + * - .WAD (DOOM engine archives) + * + * + * String policy for PhysicsFS 2.0 and later: + * + * PhysicsFS 1.0 could only deal with null-terminated ASCII strings. All high + * ASCII chars resulted in undefined behaviour, and there was no Unicode + * support at all. PhysicsFS 2.0 supports Unicode without breaking binary + * compatibility with the 1.0 API by using UTF-8 encoding of all strings + * passed in and out of the library. + * + * All strings passed through PhysicsFS are in null-terminated UTF-8 format. + * This means that if all you care about is English (ASCII characters <= 127) + * then you just use regular C strings. If you care about Unicode (and you + * should!) then you need to figure out what your platform wants, needs, and + * offers. If you are on Windows before Win2000 and build with Unicode + * support, your TCHAR strings are two bytes per character (this is called + * "UCS-2 encoding"). Any modern Windows uses UTF-16, which is two bytes + * per character for most characters, but some characters are four. You + * should convert them to UTF-8 before handing them to PhysicsFS with + * PHYSFS_utf8FromUtf16(), which handles both UTF-16 and UCS-2. If you're + * using Unix or Mac OS X, your wchar_t strings are four bytes per character + * ("UCS-4 encoding"). Use PHYSFS_utf8FromUcs4(). Mac OS X can give you UTF-8 + * directly from a CFString or NSString, and many Unixes generally give you C + * strings in UTF-8 format everywhere. If you have a single-byte high ASCII + * charset, like so-many European "codepages" you may be out of luck. We'll + * convert from "Latin1" to UTF-8 only, and never back to Latin1. If you're + * above ASCII 127, all bets are off: move to Unicode or use your platform's + * facilities. Passing a C string with high-ASCII data that isn't UTF-8 + * encoded will NOT do what you expect! + * + * Naturally, there's also PHYSFS_utf8ToUcs2(), PHYSFS_utf8ToUtf16(), and + * PHYSFS_utf8ToUcs4() to get data back into a format you like. Behind the + * scenes, PhysicsFS will use Unicode where possible: the UTF-8 strings on + * Windows will be converted and used with the multibyte Windows APIs, for + * example. + * + * PhysicsFS offers basic encoding conversion support, but not a whole string + * library. Get your stuff into whatever format you can work with. + * + * All platforms supported by PhysicsFS 2.1 and later fully support Unicode. + * We have dropped platforms that don't (OS/2, Mac OS 9, Windows 95, etc), as + * even an OS that's over a decade old should be expected to handle this well. + * If you absolutely must support one of these platforms, you should use an + * older release of PhysicsFS. + * + * Many game-specific archivers are seriously unprepared for Unicode (the + * Descent HOG/MVL and Build Engine GRP archivers, for example, only offer a + * DOS 8.3 filename, for example). Nothing can be done for these, but they + * tend to be legacy formats for existing content that was all ASCII (and + * thus, valid UTF-8) anyhow. Other formats, like .ZIP, don't explicitly + * offer Unicode support, but unofficially expect filenames to be UTF-8 + * encoded, and thus Just Work. Most everything does the right thing without + * bothering you, but it's good to be aware of these nuances in case they + * don't. + * + * + * Other stuff: + * + * Please see the file LICENSE.txt in the source's root directory for + * licensing and redistribution rights. + * + * Please see the file CREDITS.txt in the source's "docs" directory for + * a more or less complete list of who's responsible for this. + * + * \author Ryan C. Gordon. + */ + +#ifndef _INCLUDE_PHYSFS_H_ +#define _INCLUDE_PHYSFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(PHYSFS_DECL) +/* do nothing. */ +#elif (defined SWIG) +#define PHYSFS_DECL extern +#elif (defined _MSC_VER) +#define PHYSFS_DECL __declspec(dllexport) +#elif (defined __SUNPRO_C) +#define PHYSFS_DECL __global +#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) +#define PHYSFS_DECL __attribute__((visibility("default"))) +#else +#define PHYSFS_DECL +#endif + +#if defined(PHYSFS_DEPRECATED) +/* do nothing. */ +#elif (defined SWIG) /* ignore deprecated, since bindings use everything. */ +#define PHYSFS_DEPRECATED +#elif (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */ +#define PHYSFS_DEPRECATED __attribute__((deprecated)) +#else +#define PHYSFS_DEPRECATED +#endif + +#if 0 /* !!! FIXME: look into this later. */ +#if defined(PHYSFS_CALL) +/* do nothing. */ +#elif defined(__WIN32__) && !defined(__GNUC__) +#define PHYSFS_CALL __cdecl +#else +#define PHYSFS_CALL +#endif +#endif + +/** + * \typedef PHYSFS_uint8 + * \brief An unsigned, 8-bit integer type. + */ +typedef unsigned char PHYSFS_uint8; + +/** + * \typedef PHYSFS_sint8 + * \brief A signed, 8-bit integer type. + */ +typedef signed char PHYSFS_sint8; + +/** + * \typedef PHYSFS_uint16 + * \brief An unsigned, 16-bit integer type. + */ +typedef unsigned short PHYSFS_uint16; + +/** + * \typedef PHYSFS_sint16 + * \brief A signed, 16-bit integer type. + */ +typedef signed short PHYSFS_sint16; + +/** + * \typedef PHYSFS_uint32 + * \brief An unsigned, 32-bit integer type. + */ +typedef unsigned int PHYSFS_uint32; + +/** + * \typedef PHYSFS_sint32 + * \brief A signed, 32-bit integer type. + */ +typedef signed int PHYSFS_sint32; + +/** + * \typedef PHYSFS_uint64 + * \brief An unsigned, 64-bit integer type. + * \warning on platforms without any sort of 64-bit datatype, this is + * equivalent to PHYSFS_uint32! + */ + +/** + * \typedef PHYSFS_sint64 + * \brief A signed, 64-bit integer type. + * \warning on platforms without any sort of 64-bit datatype, this is + * equivalent to PHYSFS_sint32! + */ + + +#if (defined PHYSFS_NO_64BIT_SUPPORT) /* oh well. */ +typedef PHYSFS_uint32 PHYSFS_uint64; +typedef PHYSFS_sint32 PHYSFS_sint64; +#elif (defined _MSC_VER) +typedef signed __int64 PHYSFS_sint64; +typedef unsigned __int64 PHYSFS_uint64; +#else +typedef unsigned long long PHYSFS_uint64; +typedef signed long long PHYSFS_sint64; +#endif + + +#ifndef SWIG +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +/* Make sure the types really have the right sizes */ +#define PHYSFS_COMPILE_TIME_ASSERT(name, x) \ + typedef int PHYSFS_dummy_ ## name[(x) * 2 - 1] + +PHYSFS_COMPILE_TIME_ASSERT(uint8, sizeof(PHYSFS_uint8) == 1); +PHYSFS_COMPILE_TIME_ASSERT(sint8, sizeof(PHYSFS_sint8) == 1); +PHYSFS_COMPILE_TIME_ASSERT(uint16, sizeof(PHYSFS_uint16) == 2); +PHYSFS_COMPILE_TIME_ASSERT(sint16, sizeof(PHYSFS_sint16) == 2); +PHYSFS_COMPILE_TIME_ASSERT(uint32, sizeof(PHYSFS_uint32) == 4); +PHYSFS_COMPILE_TIME_ASSERT(sint32, sizeof(PHYSFS_sint32) == 4); + +#ifndef PHYSFS_NO_64BIT_SUPPORT +PHYSFS_COMPILE_TIME_ASSERT(uint64, sizeof(PHYSFS_uint64) == 8); +PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8); +#endif + +#undef PHYSFS_COMPILE_TIME_ASSERT + +#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ +#endif /* SWIG */ + + +/** + * \struct PHYSFS_File + * \brief A PhysicsFS file handle. + * + * You get a pointer to one of these when you open a file for reading, + * writing, or appending via PhysicsFS. + * + * As you can see from the lack of meaningful fields, you should treat this + * as opaque data. Don't try to manipulate the file handle, just pass the + * pointer you got, unmolested, to various PhysicsFS APIs. + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + * \sa PHYSFS_close + * \sa PHYSFS_read + * \sa PHYSFS_write + * \sa PHYSFS_seek + * \sa PHYSFS_tell + * \sa PHYSFS_eof + * \sa PHYSFS_setBuffer + * \sa PHYSFS_flush + */ +typedef struct PHYSFS_File +{ + void *opaque; /**< That's all you get. Don't touch. */ +} PHYSFS_File; + + +/** + * \def PHYSFS_file + * \brief 1.0 API compatibility define. + * + * PHYSFS_file is identical to PHYSFS_File. This #define is here for backwards + * compatibility with the 1.0 API, which had an inconsistent capitalization + * convention in this case. New code should use PHYSFS_File, as this #define + * may go away someday. + * + * \sa PHYSFS_File + */ +#define PHYSFS_file PHYSFS_File + + +/** + * \struct PHYSFS_ArchiveInfo + * \brief Information on various PhysicsFS-supported archives. + * + * This structure gives you details on what sort of archives are supported + * by this implementation of PhysicsFS. Archives tend to be things like + * ZIP files and such. + * + * \warning Not all binaries are created equal! PhysicsFS can be built with + * or without support for various archives. You can check with + * PHYSFS_supportedArchiveTypes() to see if your archive type is + * supported. + * + * \sa PHYSFS_supportedArchiveTypes + */ +typedef struct PHYSFS_ArchiveInfo +{ + const char *extension; /**< Archive file extension: "ZIP", for example. */ + const char *description; /**< Human-readable archive description. */ + const char *author; /**< Person who did support for this archive. */ + const char *url; /**< URL related to this archive */ +} PHYSFS_ArchiveInfo; + + +/** + * \struct PHYSFS_Version + * \brief Information the version of PhysicsFS in use. + * + * Represents the library's version as three levels: major revision + * (increments with massive changes, additions, and enhancements), + * minor revision (increments with backwards-compatible changes to the + * major revision), and patchlevel (increments with fixes to the minor + * revision). + * + * \sa PHYSFS_VERSION + * \sa PHYSFS_getLinkedVersion + */ +typedef struct PHYSFS_Version +{ + PHYSFS_uint8 major; /**< major revision */ + PHYSFS_uint8 minor; /**< minor revision */ + PHYSFS_uint8 patch; /**< patchlevel */ +} PHYSFS_Version; + + +#ifndef SWIG /* not available from scripting languages. */ + +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +#define PHYSFS_VER_MAJOR 2 +#define PHYSFS_VER_MINOR 1 +#define PHYSFS_VER_PATCH 0 +#endif /* DOXYGEN_SHOULD_IGNORE_THIS */ + + +/* PhysicsFS state stuff ... */ + +/** + * \def PHYSFS_VERSION(x) + * \brief Macro to determine PhysicsFS version program was compiled against. + * + * This macro fills in a PHYSFS_Version structure with the version of the + * library you compiled against. This is determined by what header the + * compiler uses. Note that if you dynamically linked the library, you might + * have a slightly newer or older version at runtime. That version can be + * determined with PHYSFS_getLinkedVersion(), which, unlike PHYSFS_VERSION, + * is not a macro. + * + * \param x A pointer to a PHYSFS_Version struct to initialize. + * + * \sa PHYSFS_Version + * \sa PHYSFS_getLinkedVersion + */ +#define PHYSFS_VERSION(x) \ +{ \ + (x)->major = PHYSFS_VER_MAJOR; \ + (x)->minor = PHYSFS_VER_MINOR; \ + (x)->patch = PHYSFS_VER_PATCH; \ +} + +#endif /* SWIG */ + + +/** + * \fn void PHYSFS_getLinkedVersion(PHYSFS_Version *ver) + * \brief Get the version of PhysicsFS that is linked against your program. + * + * If you are using a shared library (DLL) version of PhysFS, then it is + * possible that it will be different than the version you compiled against. + * + * This is a real function; the macro PHYSFS_VERSION tells you what version + * of PhysFS you compiled against: + * + * \code + * PHYSFS_Version compiled; + * PHYSFS_Version linked; + * + * PHYSFS_VERSION(&compiled); + * PHYSFS_getLinkedVersion(&linked); + * printf("We compiled against PhysFS version %d.%d.%d ...\n", + * compiled.major, compiled.minor, compiled.patch); + * printf("But we linked against PhysFS version %d.%d.%d.\n", + * linked.major, linked.minor, linked.patch); + * \endcode + * + * This function may be called safely at any time, even before PHYSFS_init(). + * + * \sa PHYSFS_VERSION + */ +PHYSFS_DECL void PHYSFS_getLinkedVersion(PHYSFS_Version *ver); + + +/** + * \fn int PHYSFS_init(const char *argv0) + * \brief Initialize the PhysicsFS library. + * + * This must be called before any other PhysicsFS function. + * + * This should be called prior to any attempts to change your process's + * current working directory. + * + * \param argv0 the argv[0] string passed to your program's mainline. + * This may be NULL on most platforms (such as ones without a + * standard main() function), but you should always try to pass + * something in here. Unix-like systems such as Linux _need_ to + * pass argv[0] from main() in here. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_deinit + * \sa PHYSFS_isInit + */ +PHYSFS_DECL int PHYSFS_init(const char *argv0); + + +/** + * \fn int PHYSFS_deinit(void) + * \brief Deinitialize the PhysicsFS library. + * + * This closes any files opened via PhysicsFS, blanks the search/write paths, + * frees memory, and invalidates all of your file handles. + * + * Note that this call can FAIL if there's a file open for writing that + * refuses to close (for example, the underlying operating system was + * buffering writes to network filesystem, and the fileserver has crashed, + * or a hard drive has failed, etc). It is usually best to close all write + * handles yourself before calling this function, so that you can gracefully + * handle a specific failure. + * + * Once successfully deinitialized, PHYSFS_init() can be called again to + * restart the subsystem. All default API states are restored at this + * point, with the exception of any custom allocator you might have + * specified, which survives between initializations. + * + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). If failure, state of PhysFS is + * undefined, and probably badly screwed up. + * + * \sa PHYSFS_init + * \sa PHYSFS_isInit + */ +PHYSFS_DECL int PHYSFS_deinit(void); + + +/** + * \fn const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) + * \brief Get a list of supported archive types. + * + * Get a list of archive types supported by this implementation of PhysicFS. + * These are the file formats usable for search path entries. This is for + * informational purposes only. Note that the extension listed is merely + * convention: if we list "ZIP", you can open a PkZip-compatible archive + * with an extension of "XYZ", if you like. + * + * The returned value is an array of pointers to PHYSFS_ArchiveInfo structures, + * with a NULL entry to signify the end of the list: + * + * \code + * PHYSFS_ArchiveInfo **i; + * + * for (i = PHYSFS_supportedArchiveTypes(); *i != NULL; i++) + * { + * printf("Supported archive: [%s], which is [%s].\n", + * (*i)->extension, (*i)->description); + * } + * \endcode + * + * The return values are pointers to internal memory, and should + * be considered READ ONLY, and never freed. The returned values are + * valid until the next call to PHYSFS_deinit(). + * + * \return READ ONLY Null-terminated array of READ ONLY structures. + */ +PHYSFS_DECL const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void); + + +/** + * \fn void PHYSFS_freeList(void *listVar) + * \brief Deallocate resources of lists returned by PhysicsFS. + * + * Certain PhysicsFS functions return lists of information that are + * dynamically allocated. Use this function to free those resources. + * + * It is safe to pass a NULL here, but doing so will cause a crash in versions + * before PhysicsFS 2.1.0. + * + * \param listVar List of information specified as freeable by this function. + * Passing NULL is safe; it is a valid no-op. + * + * \sa PHYSFS_getCdRomDirs + * \sa PHYSFS_enumerateFiles + * \sa PHYSFS_getSearchPath + */ +PHYSFS_DECL void PHYSFS_freeList(void *listVar); + + +/** + * \fn const char *PHYSFS_getLastError(void) + * \brief Get human-readable error information. + * + * \warning As of PhysicsFS 2.1, this function has been nerfed. + * Before PhysicsFS 2.1, this function was the only way to get + * error details beyond a given function's basic return value. + * This was meant to be a human-readable string in one of several + * languages, and was not useful for application parsing. This was + * a problem, because the developer and not the user chose the + * language at compile time, and the PhysicsFS maintainers had + * to (poorly) maintain a significant amount of localization work. + * The app couldn't parse the strings, even if they counted on a + * specific language, since some were dynamically generated. + * In 2.1 and later, this always returns a static string in + * English; you may use it as a key string for your own + * localizations if you like, as we'll promise not to change + * existing error strings. Also, if your application wants to + * look at specific errors, we now offer a better option: + * use PHYSFS_getLastErrorCode() instead. + * + * Get the last PhysicsFS error message as a human-readable, null-terminated + * string. This will return NULL if there's been no error since the last call + * to this function. The pointer returned by this call points to an internal + * buffer. Each thread has a unique error state associated with it, but each + * time a new error message is set, it will overwrite the previous one + * associated with that thread. It is safe to call this function at anytime, + * even before PHYSFS_init(). + * + * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same + * thread-specific error state. Calling one will wipe out the other's + * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that + * value to PHYSFS_getErrorByCode(). + * + * As of PhysicsFS 2.1, this function only presents text in the English + * language, but the strings are static, so you can use them as keys into + * your own localization dictionary. These strings are meant to be passed on + * directly to the user. + * + * Generally, applications should only concern themselves with whether a + * given function failed; however, if your code require more specifics, you + * should use PHYSFS_getLastErrorCode() instead of this function. + * + * \return READ ONLY string of last error message. + * + * \sa PHYSFS_getLastErrorCode + * \sa PHYSFS_getErrorByCode + */ +PHYSFS_DECL const char *PHYSFS_getLastError(void); + + +/** + * \fn const char *PHYSFS_getDirSeparator(void) + * \brief Get platform-dependent dir separator string. + * + * This returns "\\" on win32, "/" on Unix, and ":" on MacOS. It may be more + * than one character, depending on the platform, and your code should take + * that into account. Note that this is only useful for setting up the + * search/write paths, since access into those dirs always use '/' + * (platform-independent notation) to separate directories. This is also + * handy for getting platform-independent access when using stdio calls. + * + * \return READ ONLY null-terminated string of platform's dir separator. + */ +PHYSFS_DECL const char *PHYSFS_getDirSeparator(void); + + +/** + * \fn void PHYSFS_permitSymbolicLinks(int allow) + * \brief Enable or disable following of symbolic links. + * + * Some physical filesystems and archives contain files that are just pointers + * to other files. On the physical filesystem, opening such a link will + * (transparently) open the file that is pointed to. + * + * By default, PhysicsFS will check if a file is really a symlink during open + * calls and fail if it is. Otherwise, the link could take you outside the + * write and search paths, and compromise security. + * + * If you want to take that risk, call this function with a non-zero parameter. + * Note that this is more for sandboxing a program's scripting language, in + * case untrusted scripts try to compromise the system. Generally speaking, + * a user could very well have a legitimate reason to set up a symlink, so + * unless you feel there's a specific danger in allowing them, you should + * permit them. + * + * Symlinks are only explicitly checked when dealing with filenames + * in platform-independent notation. That is, when setting up your + * search and write paths, etc, symlinks are never checked for. + * + * Please note that PHYSFS_stat() will always check the path specified; if + * that path is a symlink, it will not be followed in any case. If symlinks + * aren't permitted through this function, PHYSFS_stat() ignores them, and + * would treat the query as if the path didn't exist at all. + * + * Symbolic link permission can be enabled or disabled at any time after + * you've called PHYSFS_init(), and is disabled by default. + * + * \param allow nonzero to permit symlinks, zero to deny linking. + * + * \sa PHYSFS_symbolicLinksPermitted + */ +PHYSFS_DECL void PHYSFS_permitSymbolicLinks(int allow); + + +/* !!! FIXME: const this? */ +/** + * \fn char **PHYSFS_getCdRomDirs(void) + * \brief Get an array of paths to available CD-ROM drives. + * + * The dirs returned are platform-dependent ("D:\" on Win32, "/cdrom" or + * whatnot on Unix). Dirs are only returned if there is a disc ready and + * accessible in the drive. So if you've got two drives (D: and E:), and only + * E: has a disc in it, then that's all you get. If the user inserts a disc + * in D: and you call this function again, you get both drives. If, on a + * Unix box, the user unmounts a disc and remounts it elsewhere, the next + * call to this function will reflect that change. + * + * This function refers to "CD-ROM" media, but it really means "inserted disc + * media," such as DVD-ROM, HD-DVD, CDRW, and Blu-Ray discs. It looks for + * filesystems, and as such won't report an audio CD, unless there's a + * mounted filesystem track on it. + * + * The returned value is an array of strings, with a NULL entry to signify the + * end of the list: + * + * \code + * char **cds = PHYSFS_getCdRomDirs(); + * char **i; + * + * for (i = cds; *i != NULL; i++) + * printf("cdrom dir [%s] is available.\n", *i); + * + * PHYSFS_freeList(cds); + * \endcode + * + * This call may block while drives spin up. Be forewarned. + * + * When you are done with the returned information, you may dispose of the + * resources by calling PHYSFS_freeList() with the returned pointer. + * + * \return Null-terminated array of null-terminated strings. + * + * \sa PHYSFS_getCdRomDirsCallback + */ +PHYSFS_DECL char **PHYSFS_getCdRomDirs(void); + + +/** + * \fn const char *PHYSFS_getBaseDir(void) + * \brief Get the path where the application resides. + * + * Helper function. + * + * Get the "base dir". This is the directory where the application was run + * from, which is probably the installation directory, and may or may not + * be the process's current working directory. + * + * You should probably use the base dir in your search path. + * + * \return READ ONLY string of base dir in platform-dependent notation. + * + * \sa PHYSFS_getPrefDir + */ +PHYSFS_DECL const char *PHYSFS_getBaseDir(void); + + +/** + * \fn const char *PHYSFS_getUserDir(void) + * \brief Get the path where user's home directory resides. + * + * \deprecated As of PhysicsFS 2.1, you probably want PHYSFS_getPrefDir(). + * + * Helper function. + * + * Get the "user dir". This is meant to be a suggestion of where a specific + * user of the system can store files. On Unix, this is her home directory. + * On systems with no concept of multiple home directories (MacOS, win95), + * this will default to something like "C:\mybasedir\users\username" + * where "username" will either be the login name, or "default" if the + * platform doesn't support multiple users, either. + * + * \return READ ONLY string of user dir in platform-dependent notation. + * + * \sa PHYSFS_getBaseDir + * \sa PHYSFS_getPrefDir + */ +PHYSFS_DECL const char *PHYSFS_getUserDir(void) PHYSFS_DEPRECATED; + + +/** + * \fn const char *PHYSFS_getWriteDir(void) + * \brief Get path where PhysicsFS will allow file writing. + * + * Get the current write dir. The default write dir is NULL. + * + * \return READ ONLY string of write dir in platform-dependent notation, + * OR NULL IF NO WRITE PATH IS CURRENTLY SET. + * + * \sa PHYSFS_setWriteDir + */ +PHYSFS_DECL const char *PHYSFS_getWriteDir(void); + + +/** + * \fn int PHYSFS_setWriteDir(const char *newDir) + * \brief Tell PhysicsFS where it may write files. + * + * Set a new write dir. This will override the previous setting. + * + * This call will fail (and fail to change the write dir) if the current + * write dir still has files open in it. + * + * \param newDir The new directory to be the root of the write dir, + * specified in platform-dependent notation. Setting to NULL + * disables the write dir, so no files can be opened for + * writing via PhysicsFS. + * \return non-zero on success, zero on failure. All attempts to open a file + * for writing via PhysicsFS will fail until this call succeeds. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_getWriteDir + */ +PHYSFS_DECL int PHYSFS_setWriteDir(const char *newDir); + + +/** + * \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath) + * \brief Add an archive or directory to the search path. + * + * \deprecated As of PhysicsFS 2.0, use PHYSFS_mount() instead. This + * function just wraps it anyhow. + * + * This function is equivalent to: + * + * \code + * PHYSFS_mount(newDir, NULL, appendToPath); + * \endcode + * + * You must use this and not PHYSFS_mount if binary compatibility with + * PhysicsFS 1.0 is important (which it may not be for many people). + * + * \sa PHYSFS_mount + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + */ +PHYSFS_DECL int PHYSFS_addToSearchPath(const char *newDir, int appendToPath) + PHYSFS_DEPRECATED; + +/** + * \fn int PHYSFS_removeFromSearchPath(const char *oldDir) + * \brief Remove a directory or archive from the search path. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_unmount() instead. This + * function just wraps it anyhow. There's no functional difference + * except the vocabulary changed from "adding to the search path" + * to "mounting" when that functionality was extended, and thus + * the preferred way to accomplish this function's work is now + * called "unmounting." + * + * This function is equivalent to: + * + * \code + * PHYSFS_unmount(oldDir); + * \endcode + * + * You must use this and not PHYSFS_unmount if binary compatibility with + * PhysicsFS 1.0 is important (which it may not be for many people). + * + * \sa PHYSFS_addToSearchPath + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_unmount + */ +PHYSFS_DECL int PHYSFS_removeFromSearchPath(const char *oldDir) + PHYSFS_DEPRECATED; + + +/** + * \fn char **PHYSFS_getSearchPath(void) + * \brief Get the current search path. + * + * The default search path is an empty list. + * + * The returned value is an array of strings, with a NULL entry to signify the + * end of the list: + * + * \code + * char **i; + * + * for (i = PHYSFS_getSearchPath(); *i != NULL; i++) + * printf("[%s] is in the search path.\n", *i); + * \endcode + * + * When you are done with the returned information, you may dispose of the + * resources by calling PHYSFS_freeList() with the returned pointer. + * + * \return Null-terminated array of null-terminated strings. NULL if there + * was a problem (read: OUT OF MEMORY). + * + * \sa PHYSFS_getSearchPathCallback + * \sa PHYSFS_addToSearchPath + * \sa PHYSFS_removeFromSearchPath + */ +PHYSFS_DECL char **PHYSFS_getSearchPath(void); + + +/** + * \fn int PHYSFS_setSaneConfig(const char *organization, const char *appName, const char *archiveExt, int includeCdRoms, int archivesFirst) + * \brief Set up sane, default paths. + * + * Helper function. + * + * The write dir will be set to the pref dir returned by + * \code PHYSFS_getPrefDir(organization, appName) \endcode, which is + * created if it doesn't exist. + * + * The above is sufficient to make sure your program's configuration directory + * is separated from other clutter, and platform-independent. + * + * The search path will be: + * + * - The Write Dir (created if it doesn't exist) + * - The Base Dir (PHYSFS_getBaseDir()) + * - All found CD-ROM dirs (optionally) + * + * These directories are then searched for files ending with the extension + * (archiveExt), which, if they are valid and supported archives, will also + * be added to the search path. If you specified "PKG" for (archiveExt), and + * there's a file named data.PKG in the base dir, it'll be checked. Archives + * can either be appended or prepended to the search path in alphabetical + * order, regardless of which directories they were found in. All archives + * are mounted in the root of the virtual file system ("/"). + * + * All of this can be accomplished from the application, but this just does it + * all for you. Feel free to add more to the search path manually, too. + * + * \param organization Name of your company/group/etc to be used as a + * dirname, so keep it small, and no-frills. + * + * \param appName Program-specific name of your program, to separate it + * from other programs using PhysicsFS. + * + * \param archiveExt File extension used by your program to specify an + * archive. For example, Quake 3 uses "pk3", even though + * they are just zipfiles. Specify NULL to not dig out + * archives automatically. Do not specify the '.' char; + * If you want to look for ZIP files, specify "ZIP" and + * not ".ZIP" ... the archive search is case-insensitive. + * + * \param includeCdRoms Non-zero to include CD-ROMs in the search path, and + * (if (archiveExt) != NULL) search them for archives. + * This may cause a significant amount of blocking + * while discs are accessed, and if there are no discs + * in the drive (or even not mounted on Unix systems), + * then they may not be made available anyhow. You may + * want to specify zero and handle the disc setup + * yourself. + * + * \param archivesFirst Non-zero to prepend the archives to the search path. + * Zero to append them. Ignored if !(archiveExt). + * + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_setSaneConfig(const char *organization, + const char *appName, + const char *archiveExt, + int includeCdRoms, + int archivesFirst); + + +/* Directory management stuff ... */ + +/** + * \fn int PHYSFS_mkdir(const char *dirName) + * \brief Create a directory. + * + * This is specified in platform-independent notation in relation to the + * write dir. All missing parent directories are also created if they + * don't exist. + * + * So if you've got the write dir set to "C:\mygame\writedir" and call + * PHYSFS_mkdir("downloads/maps") then the directories + * "C:\mygame\writedir\downloads" and "C:\mygame\writedir\downloads\maps" + * will be created if possible. If the creation of "maps" fails after we + * have successfully created "downloads", then the function leaves the + * created directory behind and reports failure. + * + * \param dirName New dir to create. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_delete + */ +PHYSFS_DECL int PHYSFS_mkdir(const char *dirName); + + +/** + * \fn int PHYSFS_delete(const char *filename) + * \brief Delete a file or directory. + * + * (filename) is specified in platform-independent notation in relation to the + * write dir. + * + * A directory must be empty before this call can delete it. + * + * Deleting a symlink will remove the link, not what it points to, regardless + * of whether you "permitSymLinks" or not. + * + * So if you've got the write dir set to "C:\mygame\writedir" and call + * PHYSFS_delete("downloads/maps/level1.map") then the file + * "C:\mygame\writedir\downloads\maps\level1.map" is removed from the + * physical filesystem, if it exists and the operating system permits the + * deletion. + * + * Note that on Unix systems, deleting a file may be successful, but the + * actual file won't be removed until all processes that have an open + * filehandle to it (including your program) close their handles. + * + * Chances are, the bits that make up the file still exist, they are just + * made available to be written over at a later point. Don't consider this + * a security method or anything. :) + * + * \param filename Filename to delete. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_delete(const char *filename); + + +/** + * \fn const char *PHYSFS_getRealDir(const char *filename) + * \brief Figure out where in the search path a file resides. + * + * The file is specified in platform-independent notation. The returned + * filename will be the element of the search path where the file was found, + * which may be a directory, or an archive. Even if there are multiple + * matches in different parts of the search path, only the first one found + * is used, just like when opening a file. + * + * So, if you look for "maps/level1.map", and C:\\mygame is in your search + * path and C:\\mygame\\maps\\level1.map exists, then "C:\mygame" is returned. + * + * If a any part of a match is a symbolic link, and you've not explicitly + * permitted symlinks, then it will be ignored, and the search for a match + * will continue. + * + * If you specify a fake directory that only exists as a mount point, it'll + * be associated with the first archive mounted there, even though that + * directory isn't necessarily contained in a real archive. + * + * \warning This will return NULL if there is no real directory associated + * with (filename). Specifically, PHYSFS_mountIo(), + * PHYSFS_mountMemory(), and PHYSFS_mountHandle() will return NULL + * even if the filename is found in the search path. Plan accordingly. + * + * \param filename file to look for. + * \return READ ONLY string of element of search path containing the + * the file in question. NULL if not found. + */ +PHYSFS_DECL const char *PHYSFS_getRealDir(const char *filename); + + +/** + * \fn char **PHYSFS_enumerateFiles(const char *dir) + * \brief Get a file listing of a search path's directory. + * + * Matching directories are interpolated. That is, if "C:\mydir" is in the + * search path and contains a directory "savegames" that contains "x.sav", + * "y.sav", and "z.sav", and there is also a "C:\userdir" in the search path + * that has a "savegames" subdirectory with "w.sav", then the following code: + * + * \code + * char **rc = PHYSFS_enumerateFiles("savegames"); + * char **i; + * + * for (i = rc; *i != NULL; i++) + * printf(" * We've got [%s].\n", *i); + * + * PHYSFS_freeList(rc); + * \endcode + * + * \...will print: + * + * \verbatim + * We've got [x.sav]. + * We've got [y.sav]. + * We've got [z.sav]. + * We've got [w.sav].\endverbatim + * + * Feel free to sort the list however you like. We only promise there will + * be no duplicates, but not what order the final list will come back in. + * + * Don't forget to call PHYSFS_freeList() with the return value from this + * function when you are done with it. + * + * \param dir directory in platform-independent notation to enumerate. + * \return Null-terminated array of null-terminated strings. + * + * \sa PHYSFS_enumerateFilesCallback + */ +PHYSFS_DECL char **PHYSFS_enumerateFiles(const char *dir); + + +/** + * \fn int PHYSFS_exists(const char *fname) + * \brief Determine if a file exists in the search path. + * + * Reports true if there is an entry anywhere in the search path by the + * name of (fname). + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you + * might end up further down in the search path than expected. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists. zero otherwise. + */ +PHYSFS_DECL int PHYSFS_exists(const char *fname); + + +/** + * \fn int PHYSFS_isDirectory(const char *fname) + * \brief Determine if a file in the search path is really a directory. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This + * function just wraps it anyhow. + * + * Determine if the first occurence of (fname) in the search path is + * really a directory entry. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, so you + * might end up further down in the search path than expected. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists and is a directory. zero otherwise. + * + * \sa PHYSFS_stat + * \sa PHYSFS_exists + */ +PHYSFS_DECL int PHYSFS_isDirectory(const char *fname) PHYSFS_DEPRECATED; + + +/** + * \fn int PHYSFS_isSymbolicLink(const char *fname) + * \brief Determine if a file in the search path is really a symbolic link. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This + * function just wraps it anyhow. + * + * Determine if the first occurence of (fname) in the search path is + * really a symbolic link. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and as such, + * this function will always return 0 in that case. + * + * \param fname filename in platform-independent notation. + * \return non-zero if filename exists and is a symlink. zero otherwise. + * + * \sa PHYSFS_stat + * \sa PHYSFS_exists + */ +PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname) PHYSFS_DEPRECATED; + + +/** + * \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename) + * \brief Get the last modification time of a file. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This + * function just wraps it anyhow. + * + * The modtime is returned as a number of seconds since the Unix epoch + * (midnight, Jan 1, 1970). The exact derivation and accuracy of this time + * depends on the particular archiver. If there is no reasonable way to + * obtain this information for a particular archiver, or there was some sort + * of error, this function returns (-1). + * + * You must use this and not PHYSFS_stat() if binary compatibility with + * PhysicsFS 2.0 is important (which it may not be for many people). + * + * \param filename filename to check, in platform-independent notation. + * \return last modified time of the file. -1 if it can't be determined. + * + * \sa PHYSFS_stat + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename) + PHYSFS_DEPRECATED; + + +/* i/o stuff... */ + +/** + * \fn PHYSFS_File *PHYSFS_openWrite(const char *filename) + * \brief Open a file for writing. + * + * Open a file for writing, in platform-independent notation and in relation + * to the write dir as the root of the writable filesystem. The specified + * file is created if it doesn't exist. If it does exist, it is truncated to + * zero bytes, and the writing offset is set to the start. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openAppend + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +PHYSFS_DECL PHYSFS_File *PHYSFS_openWrite(const char *filename); + + +/** + * \fn PHYSFS_File *PHYSFS_openAppend(const char *filename) + * \brief Open a file for appending. + * + * Open a file for writing, in platform-independent notation and in relation + * to the write dir as the root of the writable filesystem. The specified + * file is created if it doesn't exist. If it does exist, the writing offset + * is set to the end of the file, so the first write will be the byte after + * the end. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +PHYSFS_DECL PHYSFS_File *PHYSFS_openAppend(const char *filename); + + +/** + * \fn PHYSFS_File *PHYSFS_openRead(const char *filename) + * \brief Open a file for reading. + * + * Open a file for reading, in platform-independent notation. The search path + * is checked one at a time until a matching file is found, in which case an + * abstract filehandle is associated with it, and reading may be done. + * The reading offset is set to the first byte of the file. + * + * Note that entries that are symlinks are ignored if + * PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a + * symlink with this function will fail in such a case. + * + * \param filename File to open. + * \return A valid PhysicsFS filehandle on success, NULL on error. Specifics + * of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + * \sa PHYSFS_read + * \sa PHYSFS_close + */ +PHYSFS_DECL PHYSFS_File *PHYSFS_openRead(const char *filename); + + +/** + * \fn int PHYSFS_close(PHYSFS_File *handle) + * \brief Close a PhysicsFS filehandle. + * + * This call is capable of failing if the operating system was buffering + * writes to the physical media, and, now forced to write those changes to + * physical media, can not store the data for some reason. In such a case, + * the filehandle stays open. A well-written program should ALWAYS check the + * return value from the close call in addition to every writing call! + * + * \param handle handle returned from PHYSFS_open*(). + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_openRead + * \sa PHYSFS_openWrite + * \sa PHYSFS_openAppend + */ +PHYSFS_DECL int PHYSFS_close(PHYSFS_File *handle); + + +/** + * \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount) + * \brief Read data from a PhysicsFS filehandle + * + * The file must be opened for reading. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_readBytes() instead. This + * function just wraps it anyhow. This function never clarified + * what would happen if you managed to read a partial object, so + * working at the byte level makes this cleaner for everyone, + * especially now that PHYSFS_Io interfaces can be supplied by the + * application. + * + * \param handle handle returned from PHYSFS_openRead(). + * \param buffer buffer to store read data into. + * \param objSize size in bytes of objects being read from (handle). + * \param objCount number of (objSize) objects to read from (handle). + * \return number of objects read. PHYSFS_getLastError() can shed light on + * the reason this might be < (objCount), as can PHYSFS_eof(). + * -1 if complete failure. + * + * \sa PHYSFS_readBytes + * \sa PHYSFS_eof + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_read(PHYSFS_File *handle, + void *buffer, + PHYSFS_uint32 objSize, + PHYSFS_uint32 objCount) + PHYSFS_DEPRECATED; + +/** + * \fn PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, const void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount) + * \brief Write data to a PhysicsFS filehandle + * + * The file must be opened for writing. + * + * \deprecated As of PhysicsFS 2.1, use PHYSFS_writeBytes() instead. This + * function just wraps it anyhow. This function never clarified + * what would happen if you managed to write a partial object, so + * working at the byte level makes this cleaner for everyone, + * especially now that PHYSFS_Io interfaces can be supplied by the + * application. + * + * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend(). + * \param buffer buffer of bytes to write to (handle). + * \param objSize size in bytes of objects being written to (handle). + * \param objCount number of (objSize) objects to write to (handle). + * \return number of objects written. PHYSFS_getLastError() can shed light on + * the reason this might be < (objCount). -1 if complete failure. + * + * \sa PHYSFS_writeBytes + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_write(PHYSFS_File *handle, + const void *buffer, + PHYSFS_uint32 objSize, + PHYSFS_uint32 objCount) + PHYSFS_DEPRECATED; + + +/* File position stuff... */ + +/** + * \fn int PHYSFS_eof(PHYSFS_File *handle) + * \brief Check for end-of-file state on a PhysicsFS filehandle. + * + * Determine if the end of file has been reached in a PhysicsFS filehandle. + * + * \param handle handle returned from PHYSFS_openRead(). + * \return nonzero if EOF, zero if not. + * + * \sa PHYSFS_read + * \sa PHYSFS_tell + */ +PHYSFS_DECL int PHYSFS_eof(PHYSFS_File *handle); + + +/** + * \fn PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle) + * \brief Determine current position within a PhysicsFS filehandle. + * + * \param handle handle returned from PHYSFS_open*(). + * \return offset in bytes from start of file. -1 if error occurred. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_seek + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_tell(PHYSFS_File *handle); + + +/** + * \fn int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos) + * \brief Seek to a new position within a PhysicsFS filehandle. + * + * The next read or write will occur at that place. Seeking past the + * beginning or end of the file is not allowed, and causes an error. + * + * \param handle handle returned from PHYSFS_open*(). + * \param pos number of bytes from start of file to seek to. + * \return nonzero on success, zero on error. Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_tell + */ +PHYSFS_DECL int PHYSFS_seek(PHYSFS_File *handle, PHYSFS_uint64 pos); + + +/** + * \fn PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle) + * \brief Get total length of a file in bytes. + * + * Note that if another process/thread is writing to this file at the same + * time, then the information this function supplies could be incorrect + * before you get it. Use with caution, or better yet, don't use at all. + * + * \param handle handle returned from PHYSFS_open*(). + * \return size in bytes of the file. -1 if can't be determined. + * + * \sa PHYSFS_tell + * \sa PHYSFS_seek + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_File *handle); + + +/* Buffering stuff... */ + +/** + * \fn int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize) + * \brief Set up buffering for a PhysicsFS file handle. + * + * Define an i/o buffer for a file handle. A memory block of (bufsize) bytes + * will be allocated and associated with (handle). + * + * For files opened for reading, up to (bufsize) bytes are read from (handle) + * and stored in the internal buffer. Calls to PHYSFS_read() will pull + * from this buffer until it is empty, and then refill it for more reading. + * Note that compressed files, like ZIP archives, will decompress while + * buffering, so this can be handy for offsetting CPU-intensive operations. + * The buffer isn't filled until you do your next read. + * + * For files opened for writing, data will be buffered to memory until the + * buffer is full or the buffer is flushed. Closing a handle implicitly + * causes a flush...check your return values! + * + * Seeking, etc transparently accounts for buffering. + * + * You can resize an existing buffer by calling this function more than once + * on the same file. Setting the buffer size to zero will free an existing + * buffer. + * + * PhysicsFS file handles are unbuffered by default. + * + * Please check the return value of this function! Failures can include + * not being able to seek backwards in a read-only file when removing the + * buffer, not being able to allocate the buffer, and not being able to + * flush the buffer to disk, among other unexpected problems. + * + * \param handle handle returned from PHYSFS_open*(). + * \param bufsize size, in bytes, of buffer to allocate. + * \return nonzero if successful, zero on error. + * + * \sa PHYSFS_flush + * \sa PHYSFS_read + * \sa PHYSFS_write + * \sa PHYSFS_close + */ +PHYSFS_DECL int PHYSFS_setBuffer(PHYSFS_File *handle, PHYSFS_uint64 bufsize); + + +/** + * \fn int PHYSFS_flush(PHYSFS_File *handle) + * \brief Flush a buffered PhysicsFS file handle. + * + * For buffered files opened for writing, this will put the current contents + * of the buffer to disk and flag the buffer as empty if possible. + * + * For buffered files opened for reading or unbuffered files, this is a safe + * no-op, and will report success. + * + * \param handle handle returned from PHYSFS_open*(). + * \return nonzero if successful, zero on error. + * + * \sa PHYSFS_setBuffer + * \sa PHYSFS_close + */ +PHYSFS_DECL int PHYSFS_flush(PHYSFS_File *handle); + + +/* Byteorder stuff... */ + +#ifndef SWIG /* not available from scripting languages. */ + +/** + * \fn PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val) + * \brief Swap littleendian signed 16 to platform's native byte order. + * + * Take a 16-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 val); + + +/** + * \fn PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val) + * \brief Swap littleendian unsigned 16 to platform's native byte order. + * + * Take a 16-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 val); + +/** + * \fn PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val) + * \brief Swap littleendian signed 32 to platform's native byte order. + * + * Take a 32-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 val); + + +/** + * \fn PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val) + * \brief Swap littleendian unsigned 32 to platform's native byte order. + * + * Take a 32-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 val); + +/** + * \fn PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val) + * \brief Swap littleendian signed 64 to platform's native byte order. + * + * Take a 64-bit signed value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 val); + + +/** + * \fn PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val) + * \brief Swap littleendian unsigned 64 to platform's native byte order. + * + * Take a 64-bit unsigned value in littleendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 val); + + +/** + * \fn PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val) + * \brief Swap bigendian signed 16 to platform's native byte order. + * + * Take a 16-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 val); + + +/** + * \fn PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val) + * \brief Swap bigendian unsigned 16 to platform's native byte order. + * + * Take a 16-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 val); + +/** + * \fn PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val) + * \brief Swap bigendian signed 32 to platform's native byte order. + * + * Take a 32-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 val); + + +/** + * \fn PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val) + * \brief Swap bigendian unsigned 32 to platform's native byte order. + * + * Take a 32-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + */ +PHYSFS_DECL PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 val); + + +/** + * \fn PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val) + * \brief Swap bigendian signed 64 to platform's native byte order. + * + * Take a 64-bit signed value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 val); + + +/** + * \fn PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val) + * \brief Swap bigendian unsigned 64 to platform's native byte order. + * + * Take a 64-bit unsigned value in bigendian format and convert it to + * the platform's native byte order. + * + * \param val value to convert + * \return converted value. + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 val); + +#endif /* SWIG */ + + +/** + * \fn int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val) + * \brief Read and convert a signed 16-bit littleendian value. + * + * Convenience function. Read a signed 16-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_readSLE16(PHYSFS_File *file, PHYSFS_sint16 *val); + + +/** + * \fn int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val) + * \brief Read and convert an unsigned 16-bit littleendian value. + * + * Convenience function. Read an unsigned 16-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +PHYSFS_DECL int PHYSFS_readULE16(PHYSFS_File *file, PHYSFS_uint16 *val); + + +/** + * \fn int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val) + * \brief Read and convert a signed 16-bit bigendian value. + * + * Convenience function. Read a signed 16-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_readSBE16(PHYSFS_File *file, PHYSFS_sint16 *val); + + +/** + * \fn int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val) + * \brief Read and convert an unsigned 16-bit bigendian value. + * + * Convenience function. Read an unsigned 16-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +PHYSFS_DECL int PHYSFS_readUBE16(PHYSFS_File *file, PHYSFS_uint16 *val); + + +/** + * \fn int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val) + * \brief Read and convert a signed 32-bit littleendian value. + * + * Convenience function. Read a signed 32-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_readSLE32(PHYSFS_File *file, PHYSFS_sint32 *val); + + +/** + * \fn int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val) + * \brief Read and convert an unsigned 32-bit littleendian value. + * + * Convenience function. Read an unsigned 32-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +PHYSFS_DECL int PHYSFS_readULE32(PHYSFS_File *file, PHYSFS_uint32 *val); + + +/** + * \fn int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val) + * \brief Read and convert a signed 32-bit bigendian value. + * + * Convenience function. Read a signed 32-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_readSBE32(PHYSFS_File *file, PHYSFS_sint32 *val); + + +/** + * \fn int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val) + * \brief Read and convert an unsigned 32-bit bigendian value. + * + * Convenience function. Read an unsigned 32-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + */ +PHYSFS_DECL int PHYSFS_readUBE32(PHYSFS_File *file, PHYSFS_uint32 *val); + + +/** + * \fn int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val) + * \brief Read and convert a signed 64-bit littleendian value. + * + * Convenience function. Read a signed 64-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_readSLE64(PHYSFS_File *file, PHYSFS_sint64 *val); + + +/** + * \fn int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val) + * \brief Read and convert an unsigned 64-bit littleendian value. + * + * Convenience function. Read an unsigned 64-bit littleendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_readULE64(PHYSFS_File *file, PHYSFS_uint64 *val); + + +/** + * \fn int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val) + * \brief Read and convert a signed 64-bit bigendian value. + * + * Convenience function. Read a signed 64-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_sint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_readSBE64(PHYSFS_File *file, PHYSFS_sint64 *val); + + +/** + * \fn int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val) + * \brief Read and convert an unsigned 64-bit bigendian value. + * + * Convenience function. Read an unsigned 64-bit bigendian value from a + * file and convert it to the platform's native byte order. + * + * \param file PhysicsFS file handle from which to read. + * \param val pointer to where value should be stored. + * \return zero on failure, non-zero on success. If successful, (*val) will + * store the result. On failure, you can find out what went wrong + * from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_readUBE64(PHYSFS_File *file, PHYSFS_uint64 *val); + + +/** + * \fn int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val) + * \brief Convert and write a signed 16-bit littleendian value. + * + * Convenience function. Convert a signed 16-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeSLE16(PHYSFS_File *file, PHYSFS_sint16 val); + + +/** + * \fn int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val) + * \brief Convert and write an unsigned 16-bit littleendian value. + * + * Convenience function. Convert an unsigned 16-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val); + + +/** + * \fn int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val) + * \brief Convert and write a signed 16-bit bigendian value. + * + * Convenience function. Convert a signed 16-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeSBE16(PHYSFS_File *file, PHYSFS_sint16 val); + + +/** + * \fn int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val) + * \brief Convert and write an unsigned 16-bit bigendian value. + * + * Convenience function. Convert an unsigned 16-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeUBE16(PHYSFS_File *file, PHYSFS_uint16 val); + + +/** + * \fn int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val) + * \brief Convert and write a signed 32-bit littleendian value. + * + * Convenience function. Convert a signed 32-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeSLE32(PHYSFS_File *file, PHYSFS_sint32 val); + + +/** + * \fn int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val) + * \brief Convert and write an unsigned 32-bit littleendian value. + * + * Convenience function. Convert an unsigned 32-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeULE32(PHYSFS_File *file, PHYSFS_uint32 val); + + +/** + * \fn int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val) + * \brief Convert and write a signed 32-bit bigendian value. + * + * Convenience function. Convert a signed 32-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val); + + +/** + * \fn int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val) + * \brief Convert and write an unsigned 32-bit bigendian value. + * + * Convenience function. Convert an unsigned 32-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + */ +PHYSFS_DECL int PHYSFS_writeUBE32(PHYSFS_File *file, PHYSFS_uint32 val); + + +/** + * \fn int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val) + * \brief Convert and write a signed 64-bit littleendian value. + * + * Convenience function. Convert a signed 64-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_writeSLE64(PHYSFS_File *file, PHYSFS_sint64 val); + + +/** + * \fn int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val) + * \brief Convert and write an unsigned 64-bit littleendian value. + * + * Convenience function. Convert an unsigned 64-bit value from the platform's + * native byte order to littleendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_writeULE64(PHYSFS_File *file, PHYSFS_uint64 val); + + +/** + * \fn int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val) + * \brief Convert and write a signed 64-bit bigending value. + * + * Convenience function. Convert a signed 64-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_writeSBE64(PHYSFS_File *file, PHYSFS_sint64 val); + + +/** + * \fn int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val) + * \brief Convert and write an unsigned 64-bit bigendian value. + * + * Convenience function. Convert an unsigned 64-bit value from the platform's + * native byte order to bigendian and write it to a file. + * + * \param file PhysicsFS file handle to which to write. + * \param val Value to convert and write. + * \return zero on failure, non-zero on success. On failure, you can + * find out what went wrong from PHYSFS_getLastError(). + * + * \warning Remember, PHYSFS_uint64 is only 32 bits on platforms without + * any sort of 64-bit support. + */ +PHYSFS_DECL int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val); + + +/* Everything above this line is part of the PhysicsFS 1.0 API. */ + +/** + * \fn int PHYSFS_isInit(void) + * \brief Determine if the PhysicsFS library is initialized. + * + * Once PHYSFS_init() returns successfully, this will return non-zero. + * Before a successful PHYSFS_init() and after PHYSFS_deinit() returns + * successfully, this will return zero. This function is safe to call at + * any time. + * + * \return non-zero if library is initialized, zero if library is not. + * + * \sa PHYSFS_init + * \sa PHYSFS_deinit + */ +PHYSFS_DECL int PHYSFS_isInit(void); + + +/** + * \fn int PHYSFS_symbolicLinksPermitted(void) + * \brief Determine if the symbolic links are permitted. + * + * This reports the setting from the last call to PHYSFS_permitSymbolicLinks(). + * If PHYSFS_permitSymbolicLinks() hasn't been called since the library was + * last initialized, symbolic links are implicitly disabled. + * + * \return non-zero if symlinks are permitted, zero if not. + * + * \sa PHYSFS_permitSymbolicLinks + */ +PHYSFS_DECL int PHYSFS_symbolicLinksPermitted(void); + + +#ifndef SWIG /* not available from scripting languages. */ + +/** + * \struct PHYSFS_Allocator + * \brief PhysicsFS allocation function pointers. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * You create one of these structures for use with PHYSFS_setAllocator. + * Allocators are assumed to be reentrant by the caller; please mutex + * accordingly. + * + * Allocations are always discussed in 64-bits, for future expansion...we're + * on the cusp of a 64-bit transition, and we'll probably be allocating 6 + * gigabytes like it's nothing sooner or later, and I don't want to change + * this again at that point. If you're on a 32-bit platform and have to + * downcast, it's okay to return NULL if the allocation is greater than + * 4 gigabytes, since you'd have to do so anyhow. + * + * \sa PHYSFS_setAllocator + */ +typedef struct PHYSFS_Allocator +{ + int (*Init)(void); /**< Initialize. Can be NULL. Zero on failure. */ + void (*Deinit)(void); /**< Deinitialize your allocator. Can be NULL. */ + void *(*Malloc)(PHYSFS_uint64); /**< Allocate like malloc(). */ + void *(*Realloc)(void *, PHYSFS_uint64); /**< Reallocate like realloc(). */ + void (*Free)(void *); /**< Free memory from Malloc or Realloc. */ +} PHYSFS_Allocator; + + +/** + * \fn int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator) + * \brief Hook your own allocation routines into PhysicsFS. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * By default, PhysicsFS will use whatever is reasonable for a platform + * to manage dynamic memory (usually ANSI C malloc/realloc/free, but + * some platforms might use something else), but in some uncommon cases, the + * app might want more control over the library's memory management. This + * lets you redirect PhysicsFS to use your own allocation routines instead. + * You can only call this function before PHYSFS_init(); if the library is + * initialized, it'll reject your efforts to change the allocator mid-stream. + * You may call this function after PHYSFS_deinit() if you are willing to + * shut down the library and restart it with a new allocator; this is a safe + * and supported operation. The allocator remains intact between deinit/init + * calls. If you want to return to the platform's default allocator, pass a + * NULL in here. + * + * If you aren't immediately sure what to do with this function, you can + * safely ignore it altogether. + * + * \param allocator Structure containing your allocator's entry points. + * \return zero on failure, non-zero on success. This call only fails + * when used between PHYSFS_init() and PHYSFS_deinit() calls. + */ +PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator); + +#endif /* SWIG */ + + +/** + * \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath) + * \brief Add an archive or directory to the search path. + * + * If this is a duplicate, the entry is not added again, even though the + * function succeeds. You may not add the same archive to two different + * mountpoints: duplicate checking is done against the archive and not the + * mountpoint. + * + * When you mount an archive, it is added to a virtual file system...all files + * in all of the archives are interpolated into a single hierachical file + * tree. Two archives mounted at the same place (or an archive with files + * overlapping another mountpoint) may have overlapping files: in such a case, + * the file earliest in the search path is selected, and the other files are + * inaccessible to the application. This allows archives to be used to + * override previous revisions; you can use the mounting mechanism to place + * archives at a specific point in the file tree and prevent overlap; this + * is useful for downloadable mods that might trample over application data + * or each other, for example. + * + * The mountpoint does not need to exist prior to mounting, which is different + * than those familiar with the Unix concept of "mounting" may not expect. + * As well, more than one archive can be mounted to the same mountpoint, or + * mountpoints and archive contents can overlap...the interpolation mechanism + * still functions as usual. + * + * \param newDir directory or archive to add to the path, in + * platform-dependent notation. + * \param mountPoint Location in the interpolated tree that this archive + * will be "mounted", in platform-independent notation. + * NULL or "" is equivalent to "/". + * \param appendToPath nonzero to append to search path, zero to prepend. + * \return nonzero if added to path, zero on failure (bogus archive, dir + * missing, etc). Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + * \sa PHYSFS_mountIo + */ +PHYSFS_DECL int PHYSFS_mount(const char *newDir, + const char *mountPoint, + int appendToPath); + +/** + * \fn int PHYSFS_getMountPoint(const char *dir) + * \brief Determine a mounted archive's mountpoint. + * + * You give this function the name of an archive or dir you successfully + * added to the search path, and it reports the location in the interpolated + * tree where it is mounted. Files mounted with a NULL mountpoint or through + * PHYSFS_addToSearchPath() will report "/". The return value is READ ONLY + * and valid until the archive is removed from the search path. + * + * \param dir directory or archive previously added to the path, in + * platform-dependent notation. This must match the string + * used when adding, even if your string would also reference + * the same file with a different string of characters. + * \return READ-ONLY string of mount point if added to path, NULL on failure + * (bogus archive, etc) Specifics of the error can be gleaned from + * PHYSFS_getLastError(). + * + * \sa PHYSFS_removeFromSearchPath + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +PHYSFS_DECL const char *PHYSFS_getMountPoint(const char *dir); + + +#ifndef SWIG /* not available from scripting languages. */ + +/** + * \typedef PHYSFS_StringCallback + * \brief Function signature for callbacks that report strings. + * + * These are used to report a list of strings to an original caller, one + * string per callback. All strings are UTF-8 encoded. Functions should not + * try to modify or free the string's memory. + * + * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to + * functions that would return lists that need to be cleaned up with + * PHYSFS_freeList(). The callback means that the library doesn't need to + * allocate an entire list and all the strings up front. + * + * Be aware that promises data ordering in the list versions are not + * necessarily so in the callback versions. Check the documentation on + * specific APIs, but strings may not be sorted as you expect. + * + * \param data User-defined data pointer, passed through from the API + * that eventually called the callback. + * \param str The string data about which the callback is meant to inform. + * + * \sa PHYSFS_getCdRomDirsCallback + * \sa PHYSFS_getSearchPathCallback + */ +typedef void (*PHYSFS_StringCallback)(void *data, const char *str); + + +/** + * \typedef PHYSFS_EnumFilesCallback + * \brief Function signature for callbacks that enumerate files. + * + * These are used to report a list of directory entries to an original caller, + * one file/dir/symlink per callback. All strings are UTF-8 encoded. + * Functions should not try to modify or free any string's memory. + * + * These callbacks are used, starting in PhysicsFS 1.1, as an alternative to + * functions that would return lists that need to be cleaned up with + * PHYSFS_freeList(). The callback means that the library doesn't need to + * allocate an entire list and all the strings up front. + * + * Be aware that promises data ordering in the list versions are not + * necessarily so in the callback versions. Check the documentation on + * specific APIs, but strings may not be sorted as you expect. + * + * \param data User-defined data pointer, passed through from the API + * that eventually called the callback. + * \param origdir A string containing the full path, in platform-independent + * notation, of the directory containing this file. In most + * cases, this is the directory on which you requested + * enumeration, passed in the callback for your convenience. + * \param fname The filename that is being enumerated. It may not be in + * alphabetical order compared to other callbacks that have + * fired, and it will not contain the full path. You can + * recreate the fullpath with $origdir/$fname ... The file + * can be a subdirectory, a file, a symlink, etc. + * + * \sa PHYSFS_enumerateFilesCallback + */ +typedef void (*PHYSFS_EnumFilesCallback)(void *data, const char *origdir, + const char *fname); + + +/** + * \fn void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d) + * \brief Enumerate CD-ROM directories, using an application-defined callback. + * + * Internally, PHYSFS_getCdRomDirs() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_getCdRomDirs(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * detected disc: + * + * \code + * + * static void foundDisc(void *data, const char *cddir) + * { + * printf("cdrom dir [%s] is available.\n", cddir); + * } + * + * // ... + * PHYSFS_getCdRomDirsCallback(foundDisc, NULL); + * \endcode + * + * This call may block while drives spin up. Be forewarned. + * + * \param c Callback function to notify about detected drives. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_StringCallback + * \sa PHYSFS_getCdRomDirs + */ +PHYSFS_DECL void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d); + + +/** + * \fn void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d) + * \brief Enumerate the search path, using an application-defined callback. + * + * Internally, PHYSFS_getSearchPath() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_getSearchPath(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * element of the search path: + * + * \code + * + * static void printSearchPath(void *data, const char *pathItem) + * { + * printf("[%s] is in the search path.\n", pathItem); + * } + * + * // ... + * PHYSFS_getSearchPathCallback(printSearchPath, NULL); + * \endcode + * + * Elements of the search path are reported in order search priority, so the + * first archive/dir that would be examined when looking for a file is the + * first element passed through the callback. + * + * \param c Callback function to notify about search path elements. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_StringCallback + * \sa PHYSFS_getSearchPath + */ +PHYSFS_DECL void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d); + + +/** + * \fn void PHYSFS_enumerateFilesCallback(const char *dir, PHYSFS_EnumFilesCallback c, void *d) + * \brief Get a file listing of a search path's directory, using an application-defined callback. + * + * Internally, PHYSFS_enumerateFiles() just calls this function and then builds + * a list before returning to the application, so functionality is identical + * except for how the information is represented to the application. + * + * Unlike PHYSFS_enumerateFiles(), this function does not return an array. + * Rather, it calls a function specified by the application once per + * element of the search path: + * + * \code + * + * static void printDir(void *data, const char *origdir, const char *fname) + * { + * printf(" * We've got [%s] in [%s].\n", fname, origdir); + * } + * + * // ... + * PHYSFS_enumerateFilesCallback("/some/path", printDir, NULL); + * \endcode + * + * !!! FIXME: enumerateFiles() does not promise alphabetical sorting by + * !!! FIXME: case-sensitivity in the code, and doesn't promise sorting at + * !!! FIXME: all in the above docs. + * + * Items sent to the callback are not guaranteed to be in any order whatsoever. + * There is no sorting done at this level, and if you need that, you should + * probably use PHYSFS_enumerateFiles() instead, which guarantees + * alphabetical sorting. This form reports whatever is discovered in each + * archive before moving on to the next. Even within one archive, we can't + * guarantee what order it will discover data. Any sorting you find in + * these callbacks is just pure luck. Do not rely on it. As this walks + * the entire list of archives, you may receive duplicate filenames. + * + * \param dir Directory, in platform-independent notation, to enumerate. + * \param c Callback function to notify about search path elements. + * \param d Application-defined data passed to callback. Can be NULL. + * + * \sa PHYSFS_EnumFilesCallback + * \sa PHYSFS_enumerateFiles + */ +PHYSFS_DECL void PHYSFS_enumerateFilesCallback(const char *dir, + PHYSFS_EnumFilesCallback c, + void *d); + +/** + * \fn void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UCS-4 string to a UTF-8 string. + * + * UCS-4 strings are 32-bits per character: \c wchar_t on Unix. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is the same size as the source buffer. UTF-8 + * never uses more than 32-bits per character, so while it may shrink a UCS-4 + * string, it will never expand it. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * \param src Null-terminated source string in UCS-4 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +PHYSFS_DECL void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a UCS-4 string. + * + * UCS-4 strings are 32-bits per character: \c wchar_t on Unix. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is four times the size of the source buffer. + * UTF-8 uses from one to four bytes per character, but UCS-4 always uses + * four, so an entirely low-ASCII string will quadruple in size! + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UCS-4 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * \param src Null-terminated source string in UTF-8 format. + * \param dst Buffer to store converted UCS-4 string. + * \param len Size, in bytes, of destination buffer. + */ +PHYSFS_DECL void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UCS-2 string to a UTF-8 string. + * + * \warning you almost certainly should use PHYSFS_utf8FromUtf16(), which + * became available in PhysicsFS 2.1, unless you know what you're doing. + * + * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building + * with Unicode support. Please note that modern versions of Windows use + * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You + * almost certainly want PHYSFS_utf8FromUtf16() instead. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 never uses more than 32-bits per character, so while it may shrink + * a UCS-2 string, it may also expand it. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * \param src Null-terminated source string in UCS-2 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + * + * \sa PHYSFS_utf8FromUtf16 + */ +PHYSFS_DECL void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, + PHYSFS_uint64 len); + +/** + * \fn PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a UCS-2 string. + * + * \warning you almost certainly should use PHYSFS_utf8ToUtf16(), which + * became available in PhysicsFS 2.1, unless you know what you're doing. + * + * UCS-2 strings are 16-bits per character: \c TCHAR on Windows, when building + * with Unicode support. Please note that modern versions of Windows use + * UTF-16, which is an extended form of UCS-2, and not UCS-2 itself. You + * almost certainly want PHYSFS_utf8ToUtf16() instead, but you need to + * understand how that changes things, too. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 uses from one to four bytes per character, but UCS-2 always uses + * two, so an entirely low-ASCII string will double in size! + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UCS-2 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * \param src Null-terminated source string in UTF-8 format. + * \param dst Buffer to store converted UCS-2 string. + * \param len Size, in bytes, of destination buffer. + * + * \sa PHYSFS_utf8ToUtf16 + */ +PHYSFS_DECL void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, + PHYSFS_uint64 len); + +/** + * \fn void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a Latin1 string. + * + * Latin1 strings are 8-bits per character: a popular "high ASCII" encoding. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 expands latin1 codepoints over 127 from 1 to 2 bytes, so the string + * may grow in some cases. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * Please note that we do not supply a UTF-8 to Latin1 converter, since Latin1 + * can't express most Unicode codepoints. It's a legacy encoding; you should + * be converting away from it at all times. + * + * \param src Null-terminated source string in Latin1 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +PHYSFS_DECL void PHYSFS_utf8FromLatin1(const char *src, char *dst, + PHYSFS_uint64 len); + +/* Everything above this line is part of the PhysicsFS 2.0 API. */ + +/** + * \fn int PHYSFS_unmount(const char *oldDir) + * \brief Remove a directory or archive from the search path. + * + * This is functionally equivalent to PHYSFS_removeFromSearchPath(), but that + * function is deprecated to keep the vocabulary paired with PHYSFS_mount(). + * + * This must be a (case-sensitive) match to a dir or archive already in the + * search path, specified in platform-dependent notation. + * + * This call will fail (and fail to remove from the path) if the element still + * has files open in it. + * + * \param oldDir dir/archive to remove. + * \return nonzero on success, zero on failure. + * Specifics of the error can be gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_mount + */ +PHYSFS_DECL int PHYSFS_unmount(const char *oldDir); + +/** + * \fn const PHYSFS_Allocator *PHYSFS_getAllocator(void) + * \brief Discover the current allocator. + * + * (This is for limited, hardcore use. If you don't immediately see a need + * for it, you can probably ignore this forever.) + * + * This function exposes the function pointers that make up the currently used + * allocator. This can be useful for apps that want to access PhysicsFS's + * internal, default allocation routines, as well as for external code that + * wants to share the same allocator, even if the application specified their + * own. + * + * This call is only valid between PHYSFS_init() and PHYSFS_deinit() calls; + * it will return NULL if the library isn't initialized. As we can't + * guarantee the state of the internal allocators unless the library is + * initialized, you shouldn't use any allocator returned here after a call + * to PHYSFS_deinit(). + * + * Do not call the returned allocator's Init() or Deinit() methods under any + * circumstances. + * + * If you aren't immediately sure what to do with this function, you can + * safely ignore it altogether. + * + * \return Current allocator, as set by PHYSFS_setAllocator(), or PhysicsFS's + * internal, default allocator if no application defined allocator + * is currently set. Will return NULL if the library is not + * initialized. + * + * \sa PHYSFS_Allocator + * \sa PHYSFS_setAllocator + */ +PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void); + +#endif /* SWIG */ + +/** + * \enum PHYSFS_FileType + * \brief Type of a File + * + * Possible types of a file. + * + * \sa PHYSFS_stat + */ +typedef enum PHYSFS_FileType +{ + PHYSFS_FILETYPE_REGULAR, /**< a normal file */ + PHYSFS_FILETYPE_DIRECTORY, /**< a directory */ + PHYSFS_FILETYPE_SYMLINK, /**< a symlink */ + PHYSFS_FILETYPE_OTHER /**< something completely different like a device */ +} PHYSFS_FileType; + +/** + * \struct PHYSFS_Stat + * \brief Meta data for a file or directory + * + * Container for various meta data about a file in the virtual file system. + * PHYSFS_stat() uses this structure for returning the information. The time + * data will be either the number of seconds since the Unix epoch (midnight, + * Jan 1, 1970), or -1 if the information isn't available or applicable. + * The (filesize) field is measured in bytes. + * The (readonly) field tells you whether when you open a file for writing you + * are writing to the same file as if you were opening it, given you have + * enough filesystem rights to do that. !!! FIXME: this might change. + * + * \sa PHYSFS_stat + * \sa PHYSFS_FileType + */ +typedef struct PHYSFS_Stat +{ + PHYSFS_sint64 filesize; /**< size in bytes, -1 for non-files and unknown */ + PHYSFS_sint64 modtime; /**< last modification time */ + PHYSFS_sint64 createtime; /**< like modtime, but for file creation time */ + PHYSFS_sint64 accesstime; /**< like modtime, but for file access time */ + PHYSFS_FileType filetype; /**< File? Directory? Symlink? */ + int readonly; /**< non-zero if read only, zero if writable. */ +} PHYSFS_Stat; + +/** + * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat) + * \brief Get various information about a directory or a file. + * + * Obtain various information about a file or directory from the meta data. + * + * This function will never follow symbolic links. If you haven't enabled + * symlinks with PHYSFS_permitSymbolicLinks(), stat'ing a symlink will be + * treated like stat'ing a non-existant file. If symlinks are enabled, + * stat'ing a symlink will give you information on the link itself and not + * what it points to. + * + * \param fname filename to check, in platform-indepedent notation. + * \param stat pointer to structure to fill in with data about (fname). + * \return non-zero on success, zero on failure. On failure, (stat)'s + * contents are undefined. + * + * \sa PHYSFS_Stat + */ +PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat); + + +#ifndef SWIG /* not available from scripting languages. */ + +/** + * \fn void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-16 string to a UTF-8 string. + * + * UTF-16 strings are 16-bits per character (except some chars, which are + * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern + * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but + * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that + * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you + * aren't sure, you should be using UTF-16 at this point on Windows. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 never uses more than 32-bits per character, so while it may shrink + * a UTF-16 string, it may also expand it. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-8 + * sequence at the end. If the buffer length is 0, this function does nothing. + * + * \param src Null-terminated source string in UTF-16 format. + * \param dst Buffer to store converted UTF-8 string. + * \param len Size, in bytes, of destination buffer. + */ +PHYSFS_DECL void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, + PHYSFS_uint64 len); + +/** + * \fn PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len) + * \brief Convert a UTF-8 string to a UTF-16 string. + * + * UTF-16 strings are 16-bits per character (except some chars, which are + * 32-bits): \c TCHAR on Windows, when building with Unicode support. Modern + * Windows releases use UTF-16. Windows releases before 2000 used TCHAR, but + * only handled UCS-2. UTF-16 _is_ UCS-2, except for the characters that + * are 4 bytes, which aren't representable in UCS-2 at all anyhow. If you + * aren't sure, you should be using UTF-16 at this point on Windows. + * + * To ensure that the destination buffer is large enough for the conversion, + * please allocate a buffer that is double the size of the source buffer. + * UTF-8 uses from one to four bytes per character, but UTF-16 always uses + * two to four, so an entirely low-ASCII string will double in size! The + * UTF-16 characters that would take four bytes also take four bytes in UTF-8, + * so you don't need to allocate 4x the space just in case: double will do. + * + * Strings that don't fit in the destination buffer will be truncated, but + * will always be null-terminated and never have an incomplete UTF-16 + * surrogate pair at the end. If the buffer length is 0, this function does + * nothing. + * + * \param src Null-terminated source string in UTF-8 format. + * \param dst Buffer to store converted UTF-16 string. + * \param len Size, in bytes, of destination buffer. + * + * \sa PHYSFS_utf8ToUtf16 + */ +PHYSFS_DECL void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, + PHYSFS_uint64 len); + +#endif /* SWIG */ + + +/** + * \fn PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, PHYSFS_uint64 len) + * \brief Read bytes from a PhysicsFS filehandle + * + * The file must be opened for reading. + * + * \param handle handle returned from PHYSFS_openRead(). + * \param buffer buffer of at least (len) bytes to store read data into. + * \param len number of bytes being read from (handle). + * \return number of bytes read. This may be less than (len); this does not + * signify an error, necessarily (a short read may mean EOF). + * PHYSFS_getLastError() can shed light on the reason this might + * be < (len), as can PHYSFS_eof(). -1 if complete failure. + * + * \sa PHYSFS_eof + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_readBytes(PHYSFS_File *handle, void *buffer, + PHYSFS_uint64 len); + +/** + * \fn PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, const void *buffer, PHYSFS_uint64 len) + * \brief Write data to a PhysicsFS filehandle + * + * The file must be opened for writing. + * + * Please note that while (len) is an unsigned 64-bit integer, you are limited + * to 63 bits (9223372036854775807 bytes), so we can return a negative value + * on error. If length is greater than 0x7FFFFFFFFFFFFFFF, this function will + * immediately fail. For systems without a 64-bit datatype, you are limited + * to 31 bits (0x7FFFFFFF, or 2147483647 bytes). We trust most things won't + * need to do multiple gigabytes of i/o in one call anyhow, but why limit + * things? + * + * \param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend(). + * \param buffer buffer of (len) bytes to write to (handle). + * \param len number of bytes being written to (handle). + * \return number of bytes written. This may be less than (len); in the case + * of an error, the system may try to write as many bytes as possible, + * so an incomplete write might occur. PHYSFS_getLastError() can shed + * light on the reason this might be < (len). -1 if complete failure. + */ +PHYSFS_DECL PHYSFS_sint64 PHYSFS_writeBytes(PHYSFS_File *handle, + const void *buffer, + PHYSFS_uint64 len); + + +#ifndef SWIG /* not available from scripting languages. */ + +/** + * \struct PHYSFS_Io + * \brief An abstract i/o interface. + * + * \warning This is advanced, hardcore stuff. You don't need this unless you + * really know what you're doing. Most apps will not need this. + * + * Historically, PhysicsFS provided access to the physical filesystem and + * archives within that filesystem. However, sometimes you need more power + * than this. Perhaps you need to provide an archive that is entirely + * contained in RAM, or you need to bridge some other file i/o API to + * PhysicsFS, or you need to translate the bits (perhaps you have a + * a standard .zip file that's encrypted, and you need to decrypt on the fly + * for the unsuspecting zip archiver). + * + * A PHYSFS_Io is the interface that Archivers use to get archive data. + * Historically, this has mapped to file i/o to the physical filesystem, but + * as of PhysicsFS 2.1, applications can provide their own i/o implementations + * at runtime. + * + * This interface isn't necessarily a good universal fit for i/o. There are a + * few requirements of note: + * + * - They only do blocking i/o (at least, for now). + * - They need to be able to duplicate. If you have a file handle from + * fopen(), you need to be able to create a unique clone of it (so we + * have two handles to the same file that can both seek/read/etc without + * stepping on each other). + * - They need to know the size of their entire data set. + * - They need to be able to seek and rewind on demand. + * + * ...in short, you're probably not going to write an HTTP implementation. + * + * Thread safety: TO BE DECIDED. !!! FIXME + * + * \sa PHYSFS_mountIo + */ +typedef struct PHYSFS_Io +{ + /** + * \brief Binary compatibility information. + * + * This must be set to zero at this time. Future versions of this + * struct will increment this field, so we know what a given + * implementation supports. We'll presumably keep supporting older + * versions as we offer new features, though. + */ + PHYSFS_uint32 version; + + /** + * \brief Instance data for this struct. + * + * Each instance has a pointer associated with it that can be used to + * store anything it likes. This pointer is per-instance of the stream, + * so presumably it will change when calling duplicate(). This can be + * deallocated during the destroy() method. + */ + void *opaque; + + /** + * \brief Read more data. + * + * Read (len) bytes from the interface, at the current i/o position, and + * store them in (buffer). The current i/o position should move ahead + * by the number of bytes successfully read. + * + * You don't have to implement this; set it to NULL if not implemented. + * This will only be used if the file is opened for reading. If set to + * NULL, a default implementation that immediately reports failure will + * be used. + * + * \param io The i/o instance to read from. + * \param buf The buffer to store data into. It must be at least + * (len) bytes long and can't be NULL. + * \param len The number of bytes to read from the interface. + * \return number of bytes read from file, 0 on EOF, -1 if complete + * failure. + */ + PHYSFS_sint64 (*read)(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len); + + /** + * \brief Write more data. + * + * Write (len) bytes from (buffer) to the interface at the current i/o + * position. The current i/o position should move ahead by the number of + * bytes successfully written. + * + * You don't have to implement this; set it to NULL if not implemented. + * This will only be used if the file is opened for writing. If set to + * NULL, a default implementation that immediately reports failure will + * be used. + * + * You are allowed to buffer; a write can succeed here and then later + * fail when flushing. Note that PHYSFS_setBuffer() may be operating a + * level above your i/o, so you should usually not implement your + * own buffering routines. + * + * \param io The i/o instance to write to. + * \param buffer The buffer to read data from. It must be at least + * (len) bytes long and can't be NULL. + * \param len The number of bytes to read from (buffer). + * \return number of bytes written to file, -1 if complete failure. + */ + PHYSFS_sint64 (*write)(struct PHYSFS_Io *io, const void *buffer, + PHYSFS_uint64 len); + + /** + * \brief Move i/o position to a given byte offset from start. + * + * This method moves the i/o position, so the next read/write will + * be of the byte at (offset) offset. Seeks past the end of file should + * be treated as an error condition. + * + * \param io The i/o instance to seek. + * \param offset The new byte offset for the i/o position. + * \return non-zero on success, zero on error. + */ + int (*seek)(struct PHYSFS_Io *io, PHYSFS_uint64 offset); + + /** + * \brief Report current i/o position. + * + * Return bytes offset, or -1 if you aren't able to determine. A failure + * will almost certainly be fatal to further use of this stream, so you + * may not leave this unimplemented. + * + * \param io The i/o instance to query. + * \return The current byte offset for the i/o position, -1 if unknown. + */ + PHYSFS_sint64 (*tell)(struct PHYSFS_Io *io); + + /** + * \brief Determine size of the i/o instance's dataset. + * + * Return number of bytes available in the file, or -1 if you + * aren't able to determine. A failure will almost certainly be fatal + * to further use of this stream, so you may not leave this unimplemented. + * + * \param io The i/o instance to query. + * \return Total size, in bytes, of the dataset. + */ + PHYSFS_sint64 (*length)(struct PHYSFS_Io *io); + + /** + * \brief Duplicate this i/o instance. + * + * // !!! FIXME: write me. + * + * \param io The i/o instance to duplicate. + * \return A new value for a stream's (opaque) field, or NULL on error. + */ + struct PHYSFS_Io *(*duplicate)(struct PHYSFS_Io *io); + + /** + * \brief Flush resources to media, or wherever. + * + * This is the chance to report failure for writes that had claimed + * success earlier, but still had a chance to actually fail. This method + * can be NULL if flushing isn't necessary. + * + * This function may be called before destroy(), as it can report failure + * and destroy() can not. It may be called at other times, too. + * + * \param io The i/o instance to flush. + * \return Zero on error, non-zero on success. + */ + int (*flush)(struct PHYSFS_Io *io); + + /** + * \brief Cleanup and deallocate i/o instance. + * + * Free associated resources, including (opaque) if applicable. + * + * This function must always succeed: as such, it returns void. The + * system may call your flush() method before this. You may report + * failure there if necessary. This method may still be called if + * flush() fails, in which case you'll have to abandon unflushed data + * and other failing conditions and clean up. + * + * Once this method is called for a given instance, the system will assume + * it is unsafe to touch that instance again and will discard any + * references to it. + * + * \param s The i/o instance to destroy. + */ + void (*destroy)(struct PHYSFS_Io *io); +} PHYSFS_Io; + + +/** + * \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath) + * \brief Add an archive, built on a PHYSFS_Io, to the search path. + * + * \warning Unless you have some special, low-level need, you should be using + * PHYSFS_mount() instead of this. + * + * This function operates just like PHYSFS_mount(), but takes a PHYSFS_Io + * instead of a pathname. Behind the scenes, PHYSFS_mount() calls this + * function with a physical-filesystem-based PHYSFS_Io. + * + * (filename) is only used here to optimize archiver selection (if you name it + * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't + * need to refer to a real file at all, and can even be NULL. If the filename + * isn't helpful, the system will try every archiver until one works or none + * of them do. + * + * (io) must remain until the archive is unmounted. When the archive is + * unmounted, the system will call (io)->destroy(io), which will give you + * a chance to free your resources. + * + * If this function fails, (io)->destroy(io) is not called. + * + * \param io i/o instance for archive to add to the path. + * \param fname Filename that can represent this stream. Can be NULL. + * \param mountPoint Location in the interpolated tree that this archive + * will be "mounted", in platform-independent notation. + * NULL or "" is equivalent to "/". + * \param appendToPath nonzero to append to search path, zero to prepend. + * \return nonzero if added to path, zero on failure (bogus archive, stream + * i/o issue, etc). Specifics of the error can be + * gleaned from PHYSFS_getLastError(). + * + * \sa PHYSFS_unmount + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, + const char *mountPoint, int appendToPath); + +#endif /* SWIG */ + +/** + * \fn int PHYSFS_mountMemory(const void *ptr, PHYSFS_uint64 len, void (*del)(void *), const char *fname, const char *mountPoint, int appendToPath) + * \brief Add an archive, contained in a memory buffer, to the search path. + * + * \warning Unless you have some special, low-level need, you should be using + * PHYSFS_mount() instead of this. + * + * This function operates just like PHYSFS_mount(), but takes a memory buffer + * instead of a pathname. This buffer contains all the data of the archive, + * and is used instead of a real file in the physical filesystem. + * + * (filename) is only used here to optimize archiver selection (if you name it + * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't + * need to refer to a real file at all, and can even be NULL. If the filename + * isn't helpful, the system will try every archiver until one works or none + * of them do. + * + * (ptr) must remain until the archive is unmounted. When the archive is + * unmounted, the system will call (del)(ptr), which will notify you that + * the system is done with the buffer, and give you a chance to free your + * resources. (del) can be NULL, in which case the system will make no + * attempt to free the buffer. + * + * If this function fails, (del) is not called. + * + * \param ptr Address of the memory buffer containing the archive data. + * \param len Size of memory buffer, in bytes. + * \param del A callback that triggers upon unmount. Can be NULL. + * \param fname Filename that can represent this stream. Can be NULL. + * \param mountPoint Location in the interpolated tree that this archive + * will be "mounted", in platform-independent notation. + * NULL or "" is equivalent to "/". + * \param appendToPath nonzero to append to search path, zero to prepend. + * \return nonzero if added to path, zero on failure (bogus archive, etc). + * Specifics of the error can be gleaned from + * PHYSFS_getLastError(). + * + * \sa PHYSFS_unmount + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, + void (*del)(void *), const char *fname, + const char *mountPoint, int appendToPath); + + +/** + * \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, const char *mountPoint, int appendToPath) + * \brief Add an archive, contained in a PHYSFS_File handle, to the search path. + * + * \warning Unless you have some special, low-level need, you should be using + * PHYSFS_mount() instead of this. + * + * \warning Archives-in-archives may be very slow! While a PHYSFS_File can + * seek even when the data is compressed, it may do so by rewinding + * to the start and decompressing everything before the seek point. + * Normal archive usage may do a lot of seeking behind the scenes. + * As such, you might find normal archive usage extremely painful + * if mounted this way. Plan accordingly: if you, say, have a + * self-extracting .zip file, and want to mount something in it, + * compress the contents of the inner archive and make sure the outer + * .zip file doesn't compress the inner archive too. + * + * This function operates just like PHYSFS_mount(), but takes a PHYSFS_File + * handle instead of a pathname. This handle contains all the data of the + * archive, and is used instead of a real file in the physical filesystem. + * The PHYSFS_File may be backed by a real file in the physical filesystem, + * but isn't necessarily. The most popular use for this is likely to mount + * archives stored inside other archives. + * + * (filename) is only used here to optimize archiver selection (if you name it + * XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't + * need to refer to a real file at all, and can even be NULL. If the filename + * isn't helpful, the system will try every archiver until one works or none + * of them do. + * + * (file) must remain until the archive is unmounted. When the archive is + * unmounted, the system will call PHYSFS_close(file). If you need this + * handle to survive, you will have to wrap this in a PHYSFS_Io and use + * PHYSFS_mountIo() instead. + * + * If this function fails, PHYSFS_close(file) is not called. + * + * \param file The PHYSFS_File handle containing archive data. + * \param fname Filename that can represent this stream. Can be NULL. + * \param mountPoint Location in the interpolated tree that this archive + * will be "mounted", in platform-independent notation. + * NULL or "" is equivalent to "/". + * \param appendToPath nonzero to append to search path, zero to prepend. + * \return nonzero if added to path, zero on failure (bogus archive, etc). + * Specifics of the error can be gleaned from + * PHYSFS_getLastError(). + * + * \sa PHYSFS_unmount + * \sa PHYSFS_getSearchPath + * \sa PHYSFS_getMountPoint + */ +PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, + const char *mountPoint, int appendToPath); + + +/** + * \enum PHYSFS_ErrorCode + * \brief Values that represent specific causes of failure. + * + * Most of the time, you should only concern yourself with whether a given + * operation failed or not, but there may be occasions where you plan to + * handle a specific failure case gracefully, so we provide specific error + * codes. + * + * Most of these errors are a little vague, and most aren't things you can + * fix...if there's a permission error, for example, all you can really do + * is pass that information on to the user and let them figure out how to + * handle it. In most these cases, your program should only care that it + * failed to accomplish its goals, and not care specifically why. + * + * \sa PHYSFS_getLastErrorCode + * \sa PHYSFS_getErrorByCode + */ +typedef enum PHYSFS_ErrorCode +{ + PHYSFS_ERR_OK, /**< Success; no error. */ + PHYSFS_ERR_OTHER_ERROR, /**< Error not otherwise covered here. */ + PHYSFS_ERR_OUT_OF_MEMORY, /**< Memory allocation failed. */ + PHYSFS_ERR_NOT_INITIALIZED, /**< PhysicsFS is not initialized. */ + PHYSFS_ERR_IS_INITIALIZED, /**< PhysicsFS is already initialized. */ + PHYSFS_ERR_ARGV0_IS_NULL, /**< Needed argv[0], but it is NULL. */ + PHYSFS_ERR_UNSUPPORTED, /**< Operation or feature unsupported. */ + PHYSFS_ERR_PAST_EOF, /**< Attempted to access past end of file. */ + PHYSFS_ERR_FILES_STILL_OPEN, /**< Files still open. */ + PHYSFS_ERR_INVALID_ARGUMENT, /**< Bad parameter passed to an function. */ + PHYSFS_ERR_NOT_MOUNTED, /**< Requested archive/dir not mounted. */ + PHYSFS_ERR_NO_SUCH_PATH, /**< No such file, directory, or parent. */ + PHYSFS_ERR_SYMLINK_FORBIDDEN,/**< Symlink seen when not permitted. */ + PHYSFS_ERR_NO_WRITE_DIR, /**< No write dir has been specified. */ + PHYSFS_ERR_OPEN_FOR_READING, /**< Wrote to a file opened for reading. */ + PHYSFS_ERR_OPEN_FOR_WRITING, /**< Read from a file opened for writing. */ + PHYSFS_ERR_NOT_A_FILE, /**< Needed a file, got a directory (etc). */ + PHYSFS_ERR_READ_ONLY, /**< Wrote to a read-only filesystem. */ + PHYSFS_ERR_CORRUPT, /**< Corrupted data encountered. */ + PHYSFS_ERR_SYMLINK_LOOP, /**< Infinite symbolic link loop. */ + PHYSFS_ERR_IO, /**< i/o error (hardware failure, etc). */ + PHYSFS_ERR_PERMISSION, /**< Permission denied. */ + PHYSFS_ERR_NO_SPACE, /**< No space (disk full, over quota, etc) */ + PHYSFS_ERR_BAD_FILENAME, /**< Filename is bogus/insecure. */ + PHYSFS_ERR_BUSY, /**< Tried to modify a file the OS needs. */ + PHYSFS_ERR_DIR_NOT_EMPTY, /**< Tried to delete dir with files in it. */ + PHYSFS_ERR_OS_ERROR /**< Unspecified OS-level error. */ +} PHYSFS_ErrorCode; + + +/** + * \fn PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void) + * \brief Get machine-readable error information. + * + * Get the last PhysicsFS error message as an integer value. This will return + * PHYSFS_ERR_OK if there's been no error since the last call to this + * function. Each thread has a unique error state associated with it, but + * each time a new error message is set, it will overwrite the previous one + * associated with that thread. It is safe to call this function at anytime, + * even before PHYSFS_init(). + * + * PHYSFS_getLastError() and PHYSFS_getLastErrorCode() both reset the same + * thread-specific error state. Calling one will wipe out the other's + * data. If you need both, call PHYSFS_getLastErrorCode(), then pass that + * value to PHYSFS_getErrorByCode(). + * + * Generally, applications should only concern themselves with whether a + * given function failed; however, if you require more specifics, you can + * try this function to glean information, if there's some specific problem + * you're expecting and plan to handle. But with most things that involve + * file systems, the best course of action is usually to give up, report the + * problem to the user, and let them figure out what should be done about it. + * For that, you might prefer PHYSFS_getLastError() instead. + * + * \return Enumeration value that represents last reported error. + * + * \sa PHYSFS_getErrorByCode + */ +PHYSFS_DECL PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void); + + +/** + * \fn const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code) + * \brief Get human-readable description string for a given error code. + * + * Get a static string, in UTF-8 format, that represents an English + * description of a given error code. + * + * This string is guaranteed to never change (although we may add new strings + * for new error codes in later versions of PhysicsFS), so you can use it + * for keying a localization dictionary. + * + * It is safe to call this function at anytime, even before PHYSFS_init(). + * + * These strings are meant to be passed on directly to the user. + * Generally, applications should only concern themselves with whether a + * given function failed, but not care about the specifics much. + * + * Do not attempt to free the returned strings; they are read-only and you + * don't own their memory pages. + * + * \param code Error code to convert to a string. + * \return READ ONLY string of requested error message, NULL if this + * is not a valid PhysicsFS error code. Always check for NULL if + * you might be looking up an error code that didn't exist in an + * earlier version of PhysicsFS. + * + * \sa PHYSFS_getLastErrorCode + */ +PHYSFS_DECL const char *PHYSFS_getErrorByCode(PHYSFS_ErrorCode code); + +/** + * \fn void PHYSFS_setErrorCode(PHYSFS_ErrorCode code) + * \brief Set the current thread's error code. + * + * This lets you set the value that will be returned by the next call to + * PHYSFS_getLastErrorCode(). This will replace any existing error code, + * whether set by your application or internally by PhysicsFS. + * + * Error codes are stored per-thread; what you set here will not be + * accessible to another thread. + * + * Any call into PhysicsFS may change the current error code, so any code you + * set here is somewhat fragile, and thus you shouldn't build any serious + * error reporting framework on this function. The primary goal of this + * function is to allow PHYSFS_Io implementations to set the error state, + * which generally will be passed back to your application when PhysicsFS + * makes a PHYSFS_Io call that fails internally. + * + * This function doesn't care if the error code is a value known to PhysicsFS + * or not (but PHYSFS_getErrorByCode() will return NULL for unknown values). + * The value will be reported unmolested by PHYSFS_getLastErrorCode(). + * + * \param code Error code to become the current thread's new error state. + * + * \sa PHYSFS_getLastErrorCode + * \sa PHYSFS_getErrorByCode + */ +PHYSFS_DECL void PHYSFS_setErrorCode(PHYSFS_ErrorCode code); + + +/** + * \fn const char *PHYSFS_getPrefDir(const char *org, const char *app) + * \brief Get the user-and-app-specific path where files can be written. + * + * Helper function. + * + * Get the "pref dir". This is meant to be where users can write personal + * files (preferences and save games, etc) that are specific to your + * application. This directory is unique per user, per application. + * + * This function will decide the appropriate location in the native filesystem, + * create the directory if necessary, and return a string in + * platform-dependent notation, suitable for passing to PHYSFS_setWriteDir(). + * + * On Windows, this might look like: + * "C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name" + * + * On Linux, this might look like: + * "/home/bob/.local/share/My Program Name" + * + * On Mac OS X, this might look like: + * "/Users/bob/Library/Application Support/My Program Name" + * + * (etc.) + * + * You should probably use the pref dir for your write dir, and also put it + * near the beginning of your search path. Older versions of PhysicsFS + * offered only PHYSFS_getUserDir() and left you to figure out where the + * files should go under that tree. This finds the correct location + * for whatever platform, which not only changes between operating systems, + * but also versions of the same operating system. + * + * You specify the name of your organization (if it's not a real organization, + * your name or an Internet domain you own might do) and the name of your + * application. These should be proper names. + * + * Both the (org) and (app) strings may become part of a directory name, so + * please follow these rules: + * + * - Try to use the same org string (including case-sensitivity) for + * all your applications that use this function. + * - Always use a unique app string for each one, and make sure it never + * changes for an app once you've decided on it. + * - Unicode characters are legal, as long as it's UTF-8 encoded, but... + * - ...only use letters, numbers, and spaces. Avoid punctuation like + * "Game Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient. + * + * The pointer returned by this function remains valid until you call this + * function again, or call PHYSFS_deinit(). This is not necessarily a fast + * call, though, so you should call this once at startup and copy the string + * if you need it. + * + * You should assume the path returned by this function is the only safe + * place to write files (and that PHYSFS_getUserDir() and PHYSFS_getBaseDir(), + * while they might be writable, or even parents of the returned path, aren't + * where you should be writing things). + * + * \param org The name of your organization. + * \param app The name of your application. + * \return READ ONLY string of user dir in platform-dependent notation. NULL + * if there's a problem (creating directory failed, etc). + * + * \sa PHYSFS_getBaseDir + * \sa PHYSFS_getUserDir + */ +PHYSFS_DECL const char *PHYSFS_getPrefDir(const char *org, const char *app); + + +/* Everything above this line is part of the PhysicsFS 2.1 API. */ + + +#ifdef __cplusplus +} +#endif + +#endif /* !defined _INCLUDE_PHYSFS_H_ */ + +/* end of physfs.h ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_byteorder.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_byteorder.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,137 @@ +/** + * PhysicsFS; a portable, flexible file i/o abstraction. + * + * Documentation is in physfs.h. It's verbose, honest. :) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + +#ifndef PHYSFS_Swap16 +static inline PHYSFS_uint16 PHYSFS_Swap16(PHYSFS_uint16 D) +{ + return ((D<<8)|(D>>8)); +} +#endif +#ifndef PHYSFS_Swap32 +static inline PHYSFS_uint32 PHYSFS_Swap32(PHYSFS_uint32 D) +{ + return ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24)); +} +#endif +#ifndef PHYSFS_NO_64BIT_SUPPORT +#ifndef PHYSFS_Swap64 +static inline PHYSFS_uint64 PHYSFS_Swap64(PHYSFS_uint64 val) { + PHYSFS_uint32 hi, lo; + + /* Separate into high and low 32-bit values and swap them */ + lo = (PHYSFS_uint32)(val&0xFFFFFFFF); + val >>= 32; + hi = (PHYSFS_uint32)(val&0xFFFFFFFF); + val = PHYSFS_Swap32(lo); + val <<= 32; + val |= PHYSFS_Swap32(hi); + return val; +} +#endif +#else +#ifndef PHYSFS_Swap64 +/* This is mainly to keep compilers from complaining in PHYSFS code. + If there is no real 64-bit datatype, then compilers will complain about + the fake 64-bit datatype that PHYSFS provides when it compiles user code. +*/ +#define PHYSFS_Swap64(X) (X) +#endif +#endif /* PHYSFS_NO_64BIT_SUPPORT */ + + +/* Byteswap item from the specified endianness to the native endianness */ +#if PHYSFS_BYTEORDER == PHYSFS_LIL_ENDIAN +PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return x; } +PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return x; } +PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return x; } +PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return x; } +PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return x; } +PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return x; } + +PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); } +PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); } +PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); } +PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); } +PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); } +PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); } +#else +PHYSFS_uint16 PHYSFS_swapULE16(PHYSFS_uint16 x) { return PHYSFS_Swap16(x); } +PHYSFS_sint16 PHYSFS_swapSLE16(PHYSFS_sint16 x) { return PHYSFS_Swap16(x); } +PHYSFS_uint32 PHYSFS_swapULE32(PHYSFS_uint32 x) { return PHYSFS_Swap32(x); } +PHYSFS_sint32 PHYSFS_swapSLE32(PHYSFS_sint32 x) { return PHYSFS_Swap32(x); } +PHYSFS_uint64 PHYSFS_swapULE64(PHYSFS_uint64 x) { return PHYSFS_Swap64(x); } +PHYSFS_sint64 PHYSFS_swapSLE64(PHYSFS_sint64 x) { return PHYSFS_Swap64(x); } + +PHYSFS_uint16 PHYSFS_swapUBE16(PHYSFS_uint16 x) { return x; } +PHYSFS_sint16 PHYSFS_swapSBE16(PHYSFS_sint16 x) { return x; } +PHYSFS_uint32 PHYSFS_swapUBE32(PHYSFS_uint32 x) { return x; } +PHYSFS_sint32 PHYSFS_swapSBE32(PHYSFS_sint32 x) { return x; } +PHYSFS_uint64 PHYSFS_swapUBE64(PHYSFS_uint64 x) { return x; } +PHYSFS_sint64 PHYSFS_swapSBE64(PHYSFS_sint64 x) { return x; } +#endif + +static inline int readAll(PHYSFS_File *file, void *val, const size_t len) +{ + return (PHYSFS_readBytes(file, val, len) == len); +} /* readAll */ + +#define PHYSFS_BYTEORDER_READ(datatype, swaptype) \ + int PHYSFS_read##swaptype(PHYSFS_File *file, PHYSFS_##datatype *val) { \ + PHYSFS_##datatype in; \ + BAIL_IF_MACRO(val == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0); \ + BAIL_IF_MACRO(!readAll(file, &in, sizeof (in)), ERRPASS, 0); \ + *val = PHYSFS_swap##swaptype(in); \ + return 1; \ + } + +PHYSFS_BYTEORDER_READ(sint16, SLE16) +PHYSFS_BYTEORDER_READ(uint16, ULE16) +PHYSFS_BYTEORDER_READ(sint16, SBE16) +PHYSFS_BYTEORDER_READ(uint16, UBE16) +PHYSFS_BYTEORDER_READ(sint32, SLE32) +PHYSFS_BYTEORDER_READ(uint32, ULE32) +PHYSFS_BYTEORDER_READ(sint32, SBE32) +PHYSFS_BYTEORDER_READ(uint32, UBE32) +PHYSFS_BYTEORDER_READ(sint64, SLE64) +PHYSFS_BYTEORDER_READ(uint64, ULE64) +PHYSFS_BYTEORDER_READ(sint64, SBE64) +PHYSFS_BYTEORDER_READ(uint64, UBE64) + + +static inline int writeAll(PHYSFS_File *f, const void *val, const size_t len) +{ + return (PHYSFS_writeBytes(f, val, len) == len); +} /* writeAll */ + +#define PHYSFS_BYTEORDER_WRITE(datatype, swaptype) \ + int PHYSFS_write##swaptype(PHYSFS_File *file, PHYSFS_##datatype val) { \ + const PHYSFS_##datatype out = PHYSFS_swap##swaptype(val); \ + BAIL_IF_MACRO(!writeAll(file, &out, sizeof (out)), ERRPASS, 0); \ + return 1; \ + } + +PHYSFS_BYTEORDER_WRITE(sint16, SLE16) +PHYSFS_BYTEORDER_WRITE(uint16, ULE16) +PHYSFS_BYTEORDER_WRITE(sint16, SBE16) +PHYSFS_BYTEORDER_WRITE(uint16, UBE16) +PHYSFS_BYTEORDER_WRITE(sint32, SLE32) +PHYSFS_BYTEORDER_WRITE(uint32, ULE32) +PHYSFS_BYTEORDER_WRITE(sint32, SBE32) +PHYSFS_BYTEORDER_WRITE(uint32, UBE32) +PHYSFS_BYTEORDER_WRITE(sint64, SLE64) +PHYSFS_BYTEORDER_WRITE(uint64, ULE64) +PHYSFS_BYTEORDER_WRITE(sint64, SBE64) +PHYSFS_BYTEORDER_WRITE(uint64, UBE64) + +/* end of physfs_byteorder.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_casefolding.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_casefolding.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,2013 @@ +/* + * This file is part of PhysicsFS (http://icculus.org/physfs/) + * + * This data generated by physfs/extras/makecasefoldhashtable.pl ... + * Do not manually edit this file! + * + * Please see the file LICENSE.txt in the source's root directory. + */ + +#ifndef __PHYSICSFS_INTERNAL__ +#error Do not include this header from your applications. +#endif + +static const CaseFoldMapping case_fold_000[] = { + { 0x0202, 0x0203, 0x0000, 0x0000 }, + { 0x0404, 0x0454, 0x0000, 0x0000 }, + { 0x1E1E, 0x1E1F, 0x0000, 0x0000 }, + { 0x2C2C, 0x2C5C, 0x0000, 0x0000 }, + { 0x10404, 0x1042C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_001[] = { + { 0x0100, 0x0101, 0x0000, 0x0000 }, + { 0x0405, 0x0455, 0x0000, 0x0000 }, + { 0x0504, 0x0505, 0x0000, 0x0000 }, + { 0x2C2D, 0x2C5D, 0x0000, 0x0000 }, + { 0x10405, 0x1042D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_002[] = { + { 0x0200, 0x0201, 0x0000, 0x0000 }, + { 0x0406, 0x0456, 0x0000, 0x0000 }, + { 0x1E1C, 0x1E1D, 0x0000, 0x0000 }, + { 0x1F1D, 0x1F15, 0x0000, 0x0000 }, + { 0x2C2E, 0x2C5E, 0x0000, 0x0000 }, + { 0x10406, 0x1042E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_003[] = { + { 0x0102, 0x0103, 0x0000, 0x0000 }, + { 0x0407, 0x0457, 0x0000, 0x0000 }, + { 0x0506, 0x0507, 0x0000, 0x0000 }, + { 0x1F1C, 0x1F14, 0x0000, 0x0000 }, + { 0x10407, 0x1042F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_004[] = { + { 0x0206, 0x0207, 0x0000, 0x0000 }, + { 0x0400, 0x0450, 0x0000, 0x0000 }, + { 0x1E1A, 0x1E1B, 0x0000, 0x0000 }, + { 0x1F1B, 0x1F13, 0x0000, 0x0000 }, + { 0x2C28, 0x2C58, 0x0000, 0x0000 }, + { 0x10400, 0x10428, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_005[] = { + { 0x0104, 0x0105, 0x0000, 0x0000 }, + { 0x0401, 0x0451, 0x0000, 0x0000 }, + { 0x0500, 0x0501, 0x0000, 0x0000 }, + { 0x1F1A, 0x1F12, 0x0000, 0x0000 }, + { 0x2C29, 0x2C59, 0x0000, 0x0000 }, + { 0x10401, 0x10429, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_006[] = { + { 0x0204, 0x0205, 0x0000, 0x0000 }, + { 0x0402, 0x0452, 0x0000, 0x0000 }, + { 0x1E18, 0x1E19, 0x0000, 0x0000 }, + { 0x1F19, 0x1F11, 0x0000, 0x0000 }, + { 0x2C2A, 0x2C5A, 0x0000, 0x0000 }, + { 0x10402, 0x1042A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_007[] = { + { 0x0106, 0x0107, 0x0000, 0x0000 }, + { 0x0403, 0x0453, 0x0000, 0x0000 }, + { 0x0502, 0x0503, 0x0000, 0x0000 }, + { 0x1F18, 0x1F10, 0x0000, 0x0000 }, + { 0x2126, 0x03C9, 0x0000, 0x0000 }, + { 0x2C2B, 0x2C5B, 0x0000, 0x0000 }, + { 0x10403, 0x1042B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_008[] = { + { 0x020A, 0x020B, 0x0000, 0x0000 }, + { 0x040C, 0x045C, 0x0000, 0x0000 }, + { 0x1E16, 0x1E17, 0x0000, 0x0000 }, + { 0x2C24, 0x2C54, 0x0000, 0x0000 }, + { 0x1040C, 0x10434, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_009[] = { + { 0x0108, 0x0109, 0x0000, 0x0000 }, + { 0x040D, 0x045D, 0x0000, 0x0000 }, + { 0x050C, 0x050D, 0x0000, 0x0000 }, + { 0x2C25, 0x2C55, 0x0000, 0x0000 }, + { 0x1040D, 0x10435, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_010[] = { + { 0x0208, 0x0209, 0x0000, 0x0000 }, + { 0x040E, 0x045E, 0x0000, 0x0000 }, + { 0x1E14, 0x1E15, 0x0000, 0x0000 }, + { 0x212B, 0x00E5, 0x0000, 0x0000 }, + { 0x2C26, 0x2C56, 0x0000, 0x0000 }, + { 0x1040E, 0x10436, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_011[] = { + { 0x010A, 0x010B, 0x0000, 0x0000 }, + { 0x040F, 0x045F, 0x0000, 0x0000 }, + { 0x050E, 0x050F, 0x0000, 0x0000 }, + { 0x212A, 0x006B, 0x0000, 0x0000 }, + { 0x2C27, 0x2C57, 0x0000, 0x0000 }, + { 0x1040F, 0x10437, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_012[] = { + { 0x020E, 0x020F, 0x0000, 0x0000 }, + { 0x0408, 0x0458, 0x0000, 0x0000 }, + { 0x1E12, 0x1E13, 0x0000, 0x0000 }, + { 0x2C20, 0x2C50, 0x0000, 0x0000 }, + { 0x10408, 0x10430, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_013[] = { + { 0x010C, 0x010D, 0x0000, 0x0000 }, + { 0x0409, 0x0459, 0x0000, 0x0000 }, + { 0x0508, 0x0509, 0x0000, 0x0000 }, + { 0x2C21, 0x2C51, 0x0000, 0x0000 }, + { 0x10409, 0x10431, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_014[] = { + { 0x020C, 0x020D, 0x0000, 0x0000 }, + { 0x040A, 0x045A, 0x0000, 0x0000 }, + { 0x1E10, 0x1E11, 0x0000, 0x0000 }, + { 0x2C22, 0x2C52, 0x0000, 0x0000 }, + { 0x1040A, 0x10432, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_015[] = { + { 0x010E, 0x010F, 0x0000, 0x0000 }, + { 0x040B, 0x045B, 0x0000, 0x0000 }, + { 0x050A, 0x050B, 0x0000, 0x0000 }, + { 0x2C23, 0x2C53, 0x0000, 0x0000 }, + { 0x1040B, 0x10433, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_016[] = { + { 0x0212, 0x0213, 0x0000, 0x0000 }, + { 0x0414, 0x0434, 0x0000, 0x0000 }, + { 0x1E0E, 0x1E0F, 0x0000, 0x0000 }, + { 0x1F0F, 0x1F07, 0x0000, 0x0000 }, + { 0x10414, 0x1043C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_017[] = { + { 0x0110, 0x0111, 0x0000, 0x0000 }, + { 0x0415, 0x0435, 0x0000, 0x0000 }, + { 0x1F0E, 0x1F06, 0x0000, 0x0000 }, + { 0x10415, 0x1043D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_018[] = { + { 0x0210, 0x0211, 0x0000, 0x0000 }, + { 0x0416, 0x0436, 0x0000, 0x0000 }, + { 0x1E0C, 0x1E0D, 0x0000, 0x0000 }, + { 0x1F0D, 0x1F05, 0x0000, 0x0000 }, + { 0x10416, 0x1043E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_019[] = { + { 0x0112, 0x0113, 0x0000, 0x0000 }, + { 0x0417, 0x0437, 0x0000, 0x0000 }, + { 0x1F0C, 0x1F04, 0x0000, 0x0000 }, + { 0x10417, 0x1043F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_020[] = { + { 0x0216, 0x0217, 0x0000, 0x0000 }, + { 0x0410, 0x0430, 0x0000, 0x0000 }, + { 0x1E0A, 0x1E0B, 0x0000, 0x0000 }, + { 0x1F0B, 0x1F03, 0x0000, 0x0000 }, + { 0x10410, 0x10438, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_021[] = { + { 0x0114, 0x0115, 0x0000, 0x0000 }, + { 0x0411, 0x0431, 0x0000, 0x0000 }, + { 0x1F0A, 0x1F02, 0x0000, 0x0000 }, + { 0x10411, 0x10439, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_022[] = { + { 0x0214, 0x0215, 0x0000, 0x0000 }, + { 0x0412, 0x0432, 0x0000, 0x0000 }, + { 0x1E08, 0x1E09, 0x0000, 0x0000 }, + { 0x1F09, 0x1F01, 0x0000, 0x0000 }, + { 0x10412, 0x1043A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_023[] = { + { 0x0116, 0x0117, 0x0000, 0x0000 }, + { 0x0413, 0x0433, 0x0000, 0x0000 }, + { 0x1F08, 0x1F00, 0x0000, 0x0000 }, + { 0x10413, 0x1043B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_024[] = { + { 0x021A, 0x021B, 0x0000, 0x0000 }, + { 0x041C, 0x043C, 0x0000, 0x0000 }, + { 0x1E06, 0x1E07, 0x0000, 0x0000 }, + { 0x1041C, 0x10444, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_025[] = { + { 0x0118, 0x0119, 0x0000, 0x0000 }, + { 0x041D, 0x043D, 0x0000, 0x0000 }, + { 0x1041D, 0x10445, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_026[] = { + { 0x0218, 0x0219, 0x0000, 0x0000 }, + { 0x041E, 0x043E, 0x0000, 0x0000 }, + { 0x1E04, 0x1E05, 0x0000, 0x0000 }, + { 0x1041E, 0x10446, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_027[] = { + { 0x011A, 0x011B, 0x0000, 0x0000 }, + { 0x041F, 0x043F, 0x0000, 0x0000 }, + { 0x1041F, 0x10447, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_028[] = { + { 0x021E, 0x021F, 0x0000, 0x0000 }, + { 0x0418, 0x0438, 0x0000, 0x0000 }, + { 0x1E02, 0x1E03, 0x0000, 0x0000 }, + { 0x10418, 0x10440, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_029[] = { + { 0x011C, 0x011D, 0x0000, 0x0000 }, + { 0x0419, 0x0439, 0x0000, 0x0000 }, + { 0x10419, 0x10441, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_030[] = { + { 0x021C, 0x021D, 0x0000, 0x0000 }, + { 0x041A, 0x043A, 0x0000, 0x0000 }, + { 0x1E00, 0x1E01, 0x0000, 0x0000 }, + { 0x1041A, 0x10442, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_031[] = { + { 0x011E, 0x011F, 0x0000, 0x0000 }, + { 0x041B, 0x043B, 0x0000, 0x0000 }, + { 0x1041B, 0x10443, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_032[] = { + { 0x0222, 0x0223, 0x0000, 0x0000 }, + { 0x0424, 0x0444, 0x0000, 0x0000 }, + { 0x1E3E, 0x1E3F, 0x0000, 0x0000 }, + { 0x1F3F, 0x1F37, 0x0000, 0x0000 }, + { 0x2C0C, 0x2C3C, 0x0000, 0x0000 }, + { 0x10424, 0x1044C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_033[] = { + { 0x0120, 0x0121, 0x0000, 0x0000 }, + { 0x0425, 0x0445, 0x0000, 0x0000 }, + { 0x1F3E, 0x1F36, 0x0000, 0x0000 }, + { 0x2C0D, 0x2C3D, 0x0000, 0x0000 }, + { 0x10425, 0x1044D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_034[] = { + { 0x0220, 0x019E, 0x0000, 0x0000 }, + { 0x0426, 0x0446, 0x0000, 0x0000 }, + { 0x1E3C, 0x1E3D, 0x0000, 0x0000 }, + { 0x1F3D, 0x1F35, 0x0000, 0x0000 }, + { 0x2C0E, 0x2C3E, 0x0000, 0x0000 }, + { 0x10426, 0x1044E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_035[] = { + { 0x0122, 0x0123, 0x0000, 0x0000 }, + { 0x0427, 0x0447, 0x0000, 0x0000 }, + { 0x1F3C, 0x1F34, 0x0000, 0x0000 }, + { 0x2C0F, 0x2C3F, 0x0000, 0x0000 }, + { 0x10427, 0x1044F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_036[] = { + { 0x0226, 0x0227, 0x0000, 0x0000 }, + { 0x0420, 0x0440, 0x0000, 0x0000 }, + { 0x1E3A, 0x1E3B, 0x0000, 0x0000 }, + { 0x1F3B, 0x1F33, 0x0000, 0x0000 }, + { 0x2C08, 0x2C38, 0x0000, 0x0000 }, + { 0x10420, 0x10448, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_037[] = { + { 0x0124, 0x0125, 0x0000, 0x0000 }, + { 0x0421, 0x0441, 0x0000, 0x0000 }, + { 0x1F3A, 0x1F32, 0x0000, 0x0000 }, + { 0x2C09, 0x2C39, 0x0000, 0x0000 }, + { 0x10421, 0x10449, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_038[] = { + { 0x0224, 0x0225, 0x0000, 0x0000 }, + { 0x0422, 0x0442, 0x0000, 0x0000 }, + { 0x1E38, 0x1E39, 0x0000, 0x0000 }, + { 0x1F39, 0x1F31, 0x0000, 0x0000 }, + { 0x2C0A, 0x2C3A, 0x0000, 0x0000 }, + { 0x10422, 0x1044A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_039[] = { + { 0x0126, 0x0127, 0x0000, 0x0000 }, + { 0x0423, 0x0443, 0x0000, 0x0000 }, + { 0x1F38, 0x1F30, 0x0000, 0x0000 }, + { 0x2C0B, 0x2C3B, 0x0000, 0x0000 }, + { 0x10423, 0x1044B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_040[] = { + { 0x022A, 0x022B, 0x0000, 0x0000 }, + { 0x042C, 0x044C, 0x0000, 0x0000 }, + { 0x1E36, 0x1E37, 0x0000, 0x0000 }, + { 0x2C04, 0x2C34, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_041[] = { + { 0x0128, 0x0129, 0x0000, 0x0000 }, + { 0x042D, 0x044D, 0x0000, 0x0000 }, + { 0x2C05, 0x2C35, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_042[] = { + { 0x0228, 0x0229, 0x0000, 0x0000 }, + { 0x042E, 0x044E, 0x0000, 0x0000 }, + { 0x1E34, 0x1E35, 0x0000, 0x0000 }, + { 0x2C06, 0x2C36, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_043[] = { + { 0x012A, 0x012B, 0x0000, 0x0000 }, + { 0x042F, 0x044F, 0x0000, 0x0000 }, + { 0x2C07, 0x2C37, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_044[] = { + { 0x022E, 0x022F, 0x0000, 0x0000 }, + { 0x0428, 0x0448, 0x0000, 0x0000 }, + { 0x1E32, 0x1E33, 0x0000, 0x0000 }, + { 0x2C00, 0x2C30, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_045[] = { + { 0x012C, 0x012D, 0x0000, 0x0000 }, + { 0x0429, 0x0449, 0x0000, 0x0000 }, + { 0x2C01, 0x2C31, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_046[] = { + { 0x022C, 0x022D, 0x0000, 0x0000 }, + { 0x042A, 0x044A, 0x0000, 0x0000 }, + { 0x1E30, 0x1E31, 0x0000, 0x0000 }, + { 0x2C02, 0x2C32, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_047[] = { + { 0x012E, 0x012F, 0x0000, 0x0000 }, + { 0x042B, 0x044B, 0x0000, 0x0000 }, + { 0x2C03, 0x2C33, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_048[] = { + { 0x0232, 0x0233, 0x0000, 0x0000 }, + { 0x0535, 0x0565, 0x0000, 0x0000 }, + { 0x1E2E, 0x1E2F, 0x0000, 0x0000 }, + { 0x1F2F, 0x1F27, 0x0000, 0x0000 }, + { 0x2C1C, 0x2C4C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_049[] = { + { 0x0130, 0x0069, 0x0307, 0x0000 }, + { 0x0534, 0x0564, 0x0000, 0x0000 }, + { 0x1F2E, 0x1F26, 0x0000, 0x0000 }, + { 0x2C1D, 0x2C4D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_050[] = { + { 0x0230, 0x0231, 0x0000, 0x0000 }, + { 0x0537, 0x0567, 0x0000, 0x0000 }, + { 0x1E2C, 0x1E2D, 0x0000, 0x0000 }, + { 0x1F2D, 0x1F25, 0x0000, 0x0000 }, + { 0x2C1E, 0x2C4E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_051[] = { + { 0x0132, 0x0133, 0x0000, 0x0000 }, + { 0x0536, 0x0566, 0x0000, 0x0000 }, + { 0x1F2C, 0x1F24, 0x0000, 0x0000 }, + { 0x2C1F, 0x2C4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_052[] = { + { 0x0531, 0x0561, 0x0000, 0x0000 }, + { 0x1E2A, 0x1E2B, 0x0000, 0x0000 }, + { 0x1F2B, 0x1F23, 0x0000, 0x0000 }, + { 0x2C18, 0x2C48, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_053[] = { + { 0x0134, 0x0135, 0x0000, 0x0000 }, + { 0x1F2A, 0x1F22, 0x0000, 0x0000 }, + { 0x2C19, 0x2C49, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_054[] = { + { 0x0533, 0x0563, 0x0000, 0x0000 }, + { 0x1E28, 0x1E29, 0x0000, 0x0000 }, + { 0x1F29, 0x1F21, 0x0000, 0x0000 }, + { 0x2C1A, 0x2C4A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_055[] = { + { 0x0136, 0x0137, 0x0000, 0x0000 }, + { 0x0532, 0x0562, 0x0000, 0x0000 }, + { 0x1F28, 0x1F20, 0x0000, 0x0000 }, + { 0x2C1B, 0x2C4B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_056[] = { + { 0x0139, 0x013A, 0x0000, 0x0000 }, + { 0x053D, 0x056D, 0x0000, 0x0000 }, + { 0x1E26, 0x1E27, 0x0000, 0x0000 }, + { 0x2C14, 0x2C44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_057[] = { + { 0x023B, 0x023C, 0x0000, 0x0000 }, + { 0x053C, 0x056C, 0x0000, 0x0000 }, + { 0x2C15, 0x2C45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_058[] = { + { 0x013B, 0x013C, 0x0000, 0x0000 }, + { 0x053F, 0x056F, 0x0000, 0x0000 }, + { 0x1E24, 0x1E25, 0x0000, 0x0000 }, + { 0x2C16, 0x2C46, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_059[] = { + { 0x053E, 0x056E, 0x0000, 0x0000 }, + { 0x2C17, 0x2C47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_060[] = { + { 0x013D, 0x013E, 0x0000, 0x0000 }, + { 0x0539, 0x0569, 0x0000, 0x0000 }, + { 0x1E22, 0x1E23, 0x0000, 0x0000 }, + { 0x2C10, 0x2C40, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_061[] = { + { 0x0538, 0x0568, 0x0000, 0x0000 }, + { 0x2C11, 0x2C41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_062[] = { + { 0x013F, 0x0140, 0x0000, 0x0000 }, + { 0x053B, 0x056B, 0x0000, 0x0000 }, + { 0x1E20, 0x1E21, 0x0000, 0x0000 }, + { 0x2C12, 0x2C42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_063[] = { + { 0x023D, 0x019A, 0x0000, 0x0000 }, + { 0x053A, 0x056A, 0x0000, 0x0000 }, + { 0x2C13, 0x2C43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_064[] = { + { 0x0141, 0x0142, 0x0000, 0x0000 }, + { 0x0545, 0x0575, 0x0000, 0x0000 }, + { 0x1E5E, 0x1E5F, 0x0000, 0x0000 }, + { 0x1F5F, 0x1F57, 0x0000, 0x0000 }, + { 0x2161, 0x2171, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_065[] = { + { 0x0041, 0x0061, 0x0000, 0x0000 }, + { 0x0544, 0x0574, 0x0000, 0x0000 }, + { 0x2160, 0x2170, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_066[] = { + { 0x0042, 0x0062, 0x0000, 0x0000 }, + { 0x0143, 0x0144, 0x0000, 0x0000 }, + { 0x0547, 0x0577, 0x0000, 0x0000 }, + { 0x1E5C, 0x1E5D, 0x0000, 0x0000 }, + { 0x1F5D, 0x1F55, 0x0000, 0x0000 }, + { 0x2163, 0x2173, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_067[] = { + { 0x0043, 0x0063, 0x0000, 0x0000 }, + { 0x0241, 0x0294, 0x0000, 0x0000 }, + { 0x0546, 0x0576, 0x0000, 0x0000 }, + { 0x2162, 0x2172, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_068[] = { + { 0x0044, 0x0064, 0x0000, 0x0000 }, + { 0x0145, 0x0146, 0x0000, 0x0000 }, + { 0x0541, 0x0571, 0x0000, 0x0000 }, + { 0x1E5A, 0x1E5B, 0x0000, 0x0000 }, + { 0x1F5B, 0x1F53, 0x0000, 0x0000 }, + { 0x2165, 0x2175, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_069[] = { + { 0x0045, 0x0065, 0x0000, 0x0000 }, + { 0x0540, 0x0570, 0x0000, 0x0000 }, + { 0x2164, 0x2174, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_070[] = { + { 0x0046, 0x0066, 0x0000, 0x0000 }, + { 0x0147, 0x0148, 0x0000, 0x0000 }, + { 0x0345, 0x03B9, 0x0000, 0x0000 }, + { 0x0543, 0x0573, 0x0000, 0x0000 }, + { 0x1E58, 0x1E59, 0x0000, 0x0000 }, + { 0x1F59, 0x1F51, 0x0000, 0x0000 }, + { 0x2167, 0x2177, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_071[] = { + { 0x0047, 0x0067, 0x0000, 0x0000 }, + { 0x0542, 0x0572, 0x0000, 0x0000 }, + { 0x2166, 0x2176, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_072[] = { + { 0x0048, 0x0068, 0x0000, 0x0000 }, + { 0x0149, 0x02BC, 0x006E, 0x0000 }, + { 0x054D, 0x057D, 0x0000, 0x0000 }, + { 0x1E56, 0x1E57, 0x0000, 0x0000 }, + { 0x2169, 0x2179, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_073[] = { + { 0x0049, 0x0069, 0x0000, 0x0000 }, + { 0x054C, 0x057C, 0x0000, 0x0000 }, + { 0x1F56, 0x03C5, 0x0313, 0x0342 }, + { 0x2168, 0x2178, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_074[] = { + { 0x004A, 0x006A, 0x0000, 0x0000 }, + { 0x054F, 0x057F, 0x0000, 0x0000 }, + { 0x1E54, 0x1E55, 0x0000, 0x0000 }, + { 0x216B, 0x217B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_075[] = { + { 0x004B, 0x006B, 0x0000, 0x0000 }, + { 0x014A, 0x014B, 0x0000, 0x0000 }, + { 0x054E, 0x057E, 0x0000, 0x0000 }, + { 0x1F54, 0x03C5, 0x0313, 0x0301 }, + { 0x216A, 0x217A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_076[] = { + { 0x004C, 0x006C, 0x0000, 0x0000 }, + { 0x0549, 0x0579, 0x0000, 0x0000 }, + { 0x1E52, 0x1E53, 0x0000, 0x0000 }, + { 0x216D, 0x217D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_077[] = { + { 0x004D, 0x006D, 0x0000, 0x0000 }, + { 0x014C, 0x014D, 0x0000, 0x0000 }, + { 0x0548, 0x0578, 0x0000, 0x0000 }, + { 0x1F52, 0x03C5, 0x0313, 0x0300 }, + { 0x216C, 0x217C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_078[] = { + { 0x004E, 0x006E, 0x0000, 0x0000 }, + { 0x054B, 0x057B, 0x0000, 0x0000 }, + { 0x1E50, 0x1E51, 0x0000, 0x0000 }, + { 0x216F, 0x217F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_079[] = { + { 0x004F, 0x006F, 0x0000, 0x0000 }, + { 0x014E, 0x014F, 0x0000, 0x0000 }, + { 0x054A, 0x057A, 0x0000, 0x0000 }, + { 0x1F50, 0x03C5, 0x0313, 0x0000 }, + { 0x216E, 0x217E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_080[] = { + { 0x0050, 0x0070, 0x0000, 0x0000 }, + { 0x0555, 0x0585, 0x0000, 0x0000 }, + { 0x1E4E, 0x1E4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_081[] = { + { 0x0051, 0x0071, 0x0000, 0x0000 }, + { 0x0150, 0x0151, 0x0000, 0x0000 }, + { 0x0554, 0x0584, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_082[] = { + { 0x0052, 0x0072, 0x0000, 0x0000 }, + { 0x1E4C, 0x1E4D, 0x0000, 0x0000 }, + { 0x1F4D, 0x1F45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_083[] = { + { 0x0053, 0x0073, 0x0000, 0x0000 }, + { 0x0152, 0x0153, 0x0000, 0x0000 }, + { 0x0556, 0x0586, 0x0000, 0x0000 }, + { 0x1F4C, 0x1F44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_084[] = { + { 0x0054, 0x0074, 0x0000, 0x0000 }, + { 0x0551, 0x0581, 0x0000, 0x0000 }, + { 0x1E4A, 0x1E4B, 0x0000, 0x0000 }, + { 0x1F4B, 0x1F43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_085[] = { + { 0x0055, 0x0075, 0x0000, 0x0000 }, + { 0x0154, 0x0155, 0x0000, 0x0000 }, + { 0x0550, 0x0580, 0x0000, 0x0000 }, + { 0x1F4A, 0x1F42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_086[] = { + { 0x0056, 0x0076, 0x0000, 0x0000 }, + { 0x0553, 0x0583, 0x0000, 0x0000 }, + { 0x1E48, 0x1E49, 0x0000, 0x0000 }, + { 0x1F49, 0x1F41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_087[] = { + { 0x0057, 0x0077, 0x0000, 0x0000 }, + { 0x0156, 0x0157, 0x0000, 0x0000 }, + { 0x0552, 0x0582, 0x0000, 0x0000 }, + { 0x1F48, 0x1F40, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_088[] = { + { 0x0058, 0x0078, 0x0000, 0x0000 }, + { 0x1E46, 0x1E47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_089[] = { + { 0x0059, 0x0079, 0x0000, 0x0000 }, + { 0x0158, 0x0159, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_090[] = { + { 0x005A, 0x007A, 0x0000, 0x0000 }, + { 0x1E44, 0x1E45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_091[] = { + { 0x015A, 0x015B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_092[] = { + { 0x1E42, 0x1E43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_093[] = { + { 0x015C, 0x015D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_094[] = { + { 0x1E40, 0x1E41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_095[] = { + { 0x015E, 0x015F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_096[] = { + { 0x0464, 0x0465, 0x0000, 0x0000 }, + { 0x1E7E, 0x1E7F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_097[] = { + { 0x0160, 0x0161, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_098[] = { + { 0x0466, 0x0467, 0x0000, 0x0000 }, + { 0x1E7C, 0x1E7D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_099[] = { + { 0x0162, 0x0163, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_100[] = { + { 0x0460, 0x0461, 0x0000, 0x0000 }, + { 0x1E7A, 0x1E7B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_101[] = { + { 0x0164, 0x0165, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_102[] = { + { 0x0462, 0x0463, 0x0000, 0x0000 }, + { 0x1E78, 0x1E79, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_103[] = { + { 0x0166, 0x0167, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_104[] = { + { 0x046C, 0x046D, 0x0000, 0x0000 }, + { 0x1E76, 0x1E77, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_105[] = { + { 0x0168, 0x0169, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_106[] = { + { 0x046E, 0x046F, 0x0000, 0x0000 }, + { 0x1E74, 0x1E75, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_107[] = { + { 0x016A, 0x016B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_108[] = { + { 0x0468, 0x0469, 0x0000, 0x0000 }, + { 0x1E72, 0x1E73, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_109[] = { + { 0x016C, 0x016D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_110[] = { + { 0x046A, 0x046B, 0x0000, 0x0000 }, + { 0x1E70, 0x1E71, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_111[] = { + { 0x016E, 0x016F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_112[] = { + { 0x0474, 0x0475, 0x0000, 0x0000 }, + { 0x1E6E, 0x1E6F, 0x0000, 0x0000 }, + { 0x1F6F, 0x1F67, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_113[] = { + { 0x0170, 0x0171, 0x0000, 0x0000 }, + { 0x1F6E, 0x1F66, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_114[] = { + { 0x0476, 0x0477, 0x0000, 0x0000 }, + { 0x1E6C, 0x1E6D, 0x0000, 0x0000 }, + { 0x1F6D, 0x1F65, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_115[] = { + { 0x0172, 0x0173, 0x0000, 0x0000 }, + { 0x1F6C, 0x1F64, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_116[] = { + { 0x0470, 0x0471, 0x0000, 0x0000 }, + { 0x1E6A, 0x1E6B, 0x0000, 0x0000 }, + { 0x1F6B, 0x1F63, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_117[] = { + { 0x0174, 0x0175, 0x0000, 0x0000 }, + { 0x1F6A, 0x1F62, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_118[] = { + { 0x0472, 0x0473, 0x0000, 0x0000 }, + { 0x1E68, 0x1E69, 0x0000, 0x0000 }, + { 0x1F69, 0x1F61, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_119[] = { + { 0x0176, 0x0177, 0x0000, 0x0000 }, + { 0x1F68, 0x1F60, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_120[] = { + { 0x0179, 0x017A, 0x0000, 0x0000 }, + { 0x047C, 0x047D, 0x0000, 0x0000 }, + { 0x1E66, 0x1E67, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_121[] = { + { 0x0178, 0x00FF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_122[] = { + { 0x017B, 0x017C, 0x0000, 0x0000 }, + { 0x047E, 0x047F, 0x0000, 0x0000 }, + { 0x1E64, 0x1E65, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_124[] = { + { 0x017D, 0x017E, 0x0000, 0x0000 }, + { 0x0478, 0x0479, 0x0000, 0x0000 }, + { 0x1E62, 0x1E63, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_126[] = { + { 0x017F, 0x0073, 0x0000, 0x0000 }, + { 0x047A, 0x047B, 0x0000, 0x0000 }, + { 0x1E60, 0x1E61, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_128[] = { + { 0x0181, 0x0253, 0x0000, 0x0000 }, + { 0x1F9F, 0x1F27, 0x03B9, 0x0000 }, + { 0x2CAC, 0x2CAD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_129[] = { + { 0x1F9E, 0x1F26, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_130[] = { + { 0x0587, 0x0565, 0x0582, 0x0000 }, + { 0x1F9D, 0x1F25, 0x03B9, 0x0000 }, + { 0x2CAE, 0x2CAF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_131[] = { + { 0x0182, 0x0183, 0x0000, 0x0000 }, + { 0x1F9C, 0x1F24, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_132[] = { + { 0x0480, 0x0481, 0x0000, 0x0000 }, + { 0x1E9A, 0x0061, 0x02BE, 0x0000 }, + { 0x1F9B, 0x1F23, 0x03B9, 0x0000 }, + { 0x2CA8, 0x2CA9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_133[] = { + { 0x0184, 0x0185, 0x0000, 0x0000 }, + { 0x0386, 0x03AC, 0x0000, 0x0000 }, + { 0x1E9B, 0x1E61, 0x0000, 0x0000 }, + { 0x1F9A, 0x1F22, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_134[] = { + { 0x0187, 0x0188, 0x0000, 0x0000 }, + { 0x1E98, 0x0077, 0x030A, 0x0000 }, + { 0x1F99, 0x1F21, 0x03B9, 0x0000 }, + { 0x2CAA, 0x2CAB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_135[] = { + { 0x0186, 0x0254, 0x0000, 0x0000 }, + { 0x1E99, 0x0079, 0x030A, 0x0000 }, + { 0x1F98, 0x1F20, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_136[] = { + { 0x0189, 0x0256, 0x0000, 0x0000 }, + { 0x048C, 0x048D, 0x0000, 0x0000 }, + { 0x1E96, 0x0068, 0x0331, 0x0000 }, + { 0x1F97, 0x1F27, 0x03B9, 0x0000 }, + { 0x2CA4, 0x2CA5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_137[] = { + { 0x038A, 0x03AF, 0x0000, 0x0000 }, + { 0x1E97, 0x0074, 0x0308, 0x0000 }, + { 0x1F96, 0x1F26, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_138[] = { + { 0x018B, 0x018C, 0x0000, 0x0000 }, + { 0x0389, 0x03AE, 0x0000, 0x0000 }, + { 0x048E, 0x048F, 0x0000, 0x0000 }, + { 0x1E94, 0x1E95, 0x0000, 0x0000 }, + { 0x1F95, 0x1F25, 0x03B9, 0x0000 }, + { 0x2CA6, 0x2CA7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_139[] = { + { 0x018A, 0x0257, 0x0000, 0x0000 }, + { 0x0388, 0x03AD, 0x0000, 0x0000 }, + { 0x1F94, 0x1F24, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_140[] = { + { 0x038F, 0x03CE, 0x0000, 0x0000 }, + { 0x1E92, 0x1E93, 0x0000, 0x0000 }, + { 0x1F93, 0x1F23, 0x03B9, 0x0000 }, + { 0x2CA0, 0x2CA1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_141[] = { + { 0x038E, 0x03CD, 0x0000, 0x0000 }, + { 0x1F92, 0x1F22, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_142[] = { + { 0x018F, 0x0259, 0x0000, 0x0000 }, + { 0x048A, 0x048B, 0x0000, 0x0000 }, + { 0x1E90, 0x1E91, 0x0000, 0x0000 }, + { 0x1F91, 0x1F21, 0x03B9, 0x0000 }, + { 0x2CA2, 0x2CA3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_143[] = { + { 0x018E, 0x01DD, 0x0000, 0x0000 }, + { 0x038C, 0x03CC, 0x0000, 0x0000 }, + { 0x1F90, 0x1F20, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_144[] = { + { 0x0191, 0x0192, 0x0000, 0x0000 }, + { 0x0393, 0x03B3, 0x0000, 0x0000 }, + { 0x0494, 0x0495, 0x0000, 0x0000 }, + { 0x1E8E, 0x1E8F, 0x0000, 0x0000 }, + { 0x1F8F, 0x1F07, 0x03B9, 0x0000 }, + { 0x2CBC, 0x2CBD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_145[] = { + { 0x0190, 0x025B, 0x0000, 0x0000 }, + { 0x0392, 0x03B2, 0x0000, 0x0000 }, + { 0x1F8E, 0x1F06, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_146[] = { + { 0x0193, 0x0260, 0x0000, 0x0000 }, + { 0x0391, 0x03B1, 0x0000, 0x0000 }, + { 0x0496, 0x0497, 0x0000, 0x0000 }, + { 0x1E8C, 0x1E8D, 0x0000, 0x0000 }, + { 0x1F8D, 0x1F05, 0x03B9, 0x0000 }, + { 0x24B6, 0x24D0, 0x0000, 0x0000 }, + { 0x2CBE, 0x2CBF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_147[] = { + { 0x0390, 0x03B9, 0x0308, 0x0301 }, + { 0x1F8C, 0x1F04, 0x03B9, 0x0000 }, + { 0x24B7, 0x24D1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_148[] = { + { 0x0397, 0x03B7, 0x0000, 0x0000 }, + { 0x0490, 0x0491, 0x0000, 0x0000 }, + { 0x1E8A, 0x1E8B, 0x0000, 0x0000 }, + { 0x1F8B, 0x1F03, 0x03B9, 0x0000 }, + { 0x2CB8, 0x2CB9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_149[] = { + { 0x0194, 0x0263, 0x0000, 0x0000 }, + { 0x0396, 0x03B6, 0x0000, 0x0000 }, + { 0x1F8A, 0x1F02, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_150[] = { + { 0x0197, 0x0268, 0x0000, 0x0000 }, + { 0x0395, 0x03B5, 0x0000, 0x0000 }, + { 0x0492, 0x0493, 0x0000, 0x0000 }, + { 0x1E88, 0x1E89, 0x0000, 0x0000 }, + { 0x1F89, 0x1F01, 0x03B9, 0x0000 }, + { 0x2CBA, 0x2CBB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_151[] = { + { 0x0196, 0x0269, 0x0000, 0x0000 }, + { 0x0394, 0x03B4, 0x0000, 0x0000 }, + { 0x1F88, 0x1F00, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_152[] = { + { 0x039B, 0x03BB, 0x0000, 0x0000 }, + { 0x049C, 0x049D, 0x0000, 0x0000 }, + { 0x1E86, 0x1E87, 0x0000, 0x0000 }, + { 0x1F87, 0x1F07, 0x03B9, 0x0000 }, + { 0x24BC, 0x24D6, 0x0000, 0x0000 }, + { 0x2CB4, 0x2CB5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_153[] = { + { 0x0198, 0x0199, 0x0000, 0x0000 }, + { 0x039A, 0x03BA, 0x0000, 0x0000 }, + { 0x1F86, 0x1F06, 0x03B9, 0x0000 }, + { 0x24BD, 0x24D7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_154[] = { + { 0x0399, 0x03B9, 0x0000, 0x0000 }, + { 0x049E, 0x049F, 0x0000, 0x0000 }, + { 0x1E84, 0x1E85, 0x0000, 0x0000 }, + { 0x1F85, 0x1F05, 0x03B9, 0x0000 }, + { 0x24BE, 0x24D8, 0x0000, 0x0000 }, + { 0x2CB6, 0x2CB7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_155[] = { + { 0x0398, 0x03B8, 0x0000, 0x0000 }, + { 0x1F84, 0x1F04, 0x03B9, 0x0000 }, + { 0x24BF, 0x24D9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_156[] = { + { 0x019D, 0x0272, 0x0000, 0x0000 }, + { 0x039F, 0x03BF, 0x0000, 0x0000 }, + { 0x0498, 0x0499, 0x0000, 0x0000 }, + { 0x1E82, 0x1E83, 0x0000, 0x0000 }, + { 0x1F83, 0x1F03, 0x03B9, 0x0000 }, + { 0x24B8, 0x24D2, 0x0000, 0x0000 }, + { 0x2CB0, 0x2CB1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_157[] = { + { 0x019C, 0x026F, 0x0000, 0x0000 }, + { 0x039E, 0x03BE, 0x0000, 0x0000 }, + { 0x1F82, 0x1F02, 0x03B9, 0x0000 }, + { 0x24B9, 0x24D3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_158[] = { + { 0x019F, 0x0275, 0x0000, 0x0000 }, + { 0x039D, 0x03BD, 0x0000, 0x0000 }, + { 0x049A, 0x049B, 0x0000, 0x0000 }, + { 0x1E80, 0x1E81, 0x0000, 0x0000 }, + { 0x1F81, 0x1F01, 0x03B9, 0x0000 }, + { 0x24BA, 0x24D4, 0x0000, 0x0000 }, + { 0x2CB2, 0x2CB3, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_159[] = { + { 0x039C, 0x03BC, 0x0000, 0x0000 }, + { 0x1F80, 0x1F00, 0x03B9, 0x0000 }, + { 0x24BB, 0x24D5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_160[] = { + { 0x03A3, 0x03C3, 0x0000, 0x0000 }, + { 0x04A4, 0x04A5, 0x0000, 0x0000 }, + { 0x10B0, 0x2D10, 0x0000, 0x0000 }, + { 0x1EBE, 0x1EBF, 0x0000, 0x0000 }, + { 0x2C8C, 0x2C8D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_161[] = { + { 0x01A0, 0x01A1, 0x0000, 0x0000 }, + { 0x10B1, 0x2D11, 0x0000, 0x0000 }, + { 0x1FBE, 0x03B9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_162[] = { + { 0x03A1, 0x03C1, 0x0000, 0x0000 }, + { 0x04A6, 0x04A7, 0x0000, 0x0000 }, + { 0x10B2, 0x2D12, 0x0000, 0x0000 }, + { 0x1EBC, 0x1EBD, 0x0000, 0x0000 }, + { 0x2C8E, 0x2C8F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_163[] = { + { 0x01A2, 0x01A3, 0x0000, 0x0000 }, + { 0x03A0, 0x03C0, 0x0000, 0x0000 }, + { 0x10B3, 0x2D13, 0x0000, 0x0000 }, + { 0x1FBC, 0x03B1, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_164[] = { + { 0x03A7, 0x03C7, 0x0000, 0x0000 }, + { 0x04A0, 0x04A1, 0x0000, 0x0000 }, + { 0x10B4, 0x2D14, 0x0000, 0x0000 }, + { 0x1EBA, 0x1EBB, 0x0000, 0x0000 }, + { 0x1FBB, 0x1F71, 0x0000, 0x0000 }, + { 0x2C88, 0x2C89, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_165[] = { + { 0x01A4, 0x01A5, 0x0000, 0x0000 }, + { 0x03A6, 0x03C6, 0x0000, 0x0000 }, + { 0x10B5, 0x2D15, 0x0000, 0x0000 }, + { 0x1FBA, 0x1F70, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_166[] = { + { 0x01A7, 0x01A8, 0x0000, 0x0000 }, + { 0x03A5, 0x03C5, 0x0000, 0x0000 }, + { 0x04A2, 0x04A3, 0x0000, 0x0000 }, + { 0x10B6, 0x2D16, 0x0000, 0x0000 }, + { 0x1EB8, 0x1EB9, 0x0000, 0x0000 }, + { 0x1FB9, 0x1FB1, 0x0000, 0x0000 }, + { 0x2C8A, 0x2C8B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_167[] = { + { 0x01A6, 0x0280, 0x0000, 0x0000 }, + { 0x03A4, 0x03C4, 0x0000, 0x0000 }, + { 0x10B7, 0x2D17, 0x0000, 0x0000 }, + { 0x1FB8, 0x1FB0, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_168[] = { + { 0x01A9, 0x0283, 0x0000, 0x0000 }, + { 0x03AB, 0x03CB, 0x0000, 0x0000 }, + { 0x04AC, 0x04AD, 0x0000, 0x0000 }, + { 0x10B8, 0x2D18, 0x0000, 0x0000 }, + { 0x1EB6, 0x1EB7, 0x0000, 0x0000 }, + { 0x1FB7, 0x03B1, 0x0342, 0x03B9 }, + { 0x2C84, 0x2C85, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_169[] = { + { 0x03AA, 0x03CA, 0x0000, 0x0000 }, + { 0x10B9, 0x2D19, 0x0000, 0x0000 }, + { 0x1FB6, 0x03B1, 0x0342, 0x0000 } +}; + +static const CaseFoldMapping case_fold_170[] = { + { 0x03A9, 0x03C9, 0x0000, 0x0000 }, + { 0x04AE, 0x04AF, 0x0000, 0x0000 }, + { 0x10BA, 0x2D1A, 0x0000, 0x0000 }, + { 0x1EB4, 0x1EB5, 0x0000, 0x0000 }, + { 0x2C86, 0x2C87, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_171[] = { + { 0x03A8, 0x03C8, 0x0000, 0x0000 }, + { 0x10BB, 0x2D1B, 0x0000, 0x0000 }, + { 0x1FB4, 0x03AC, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_172[] = { + { 0x04A8, 0x04A9, 0x0000, 0x0000 }, + { 0x10BC, 0x2D1C, 0x0000, 0x0000 }, + { 0x1EB2, 0x1EB3, 0x0000, 0x0000 }, + { 0x1FB3, 0x03B1, 0x03B9, 0x0000 }, + { 0x2C80, 0x2C81, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_173[] = { + { 0x01AC, 0x01AD, 0x0000, 0x0000 }, + { 0x10BD, 0x2D1D, 0x0000, 0x0000 }, + { 0x1FB2, 0x1F70, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_174[] = { + { 0x01AF, 0x01B0, 0x0000, 0x0000 }, + { 0x04AA, 0x04AB, 0x0000, 0x0000 }, + { 0x10BE, 0x2D1E, 0x0000, 0x0000 }, + { 0x1EB0, 0x1EB1, 0x0000, 0x0000 }, + { 0x2C82, 0x2C83, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_175[] = { + { 0x01AE, 0x0288, 0x0000, 0x0000 }, + { 0x10BF, 0x2D1F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_176[] = { + { 0x01B1, 0x028A, 0x0000, 0x0000 }, + { 0x04B4, 0x04B5, 0x0000, 0x0000 }, + { 0x10A0, 0x2D00, 0x0000, 0x0000 }, + { 0x1EAE, 0x1EAF, 0x0000, 0x0000 }, + { 0x1FAF, 0x1F67, 0x03B9, 0x0000 }, + { 0x2C9C, 0x2C9D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_177[] = { + { 0x10A1, 0x2D01, 0x0000, 0x0000 }, + { 0x1FAE, 0x1F66, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_178[] = { + { 0x01B3, 0x01B4, 0x0000, 0x0000 }, + { 0x04B6, 0x04B7, 0x0000, 0x0000 }, + { 0x10A2, 0x2D02, 0x0000, 0x0000 }, + { 0x1EAC, 0x1EAD, 0x0000, 0x0000 }, + { 0x1FAD, 0x1F65, 0x03B9, 0x0000 }, + { 0x2C9E, 0x2C9F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_179[] = { + { 0x01B2, 0x028B, 0x0000, 0x0000 }, + { 0x03B0, 0x03C5, 0x0308, 0x0301 }, + { 0x10A3, 0x2D03, 0x0000, 0x0000 }, + { 0x1FAC, 0x1F64, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_180[] = { + { 0x01B5, 0x01B6, 0x0000, 0x0000 }, + { 0x04B0, 0x04B1, 0x0000, 0x0000 }, + { 0x10A4, 0x2D04, 0x0000, 0x0000 }, + { 0x1EAA, 0x1EAB, 0x0000, 0x0000 }, + { 0x1FAB, 0x1F63, 0x03B9, 0x0000 }, + { 0x2C98, 0x2C99, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_181[] = { + { 0x00B5, 0x03BC, 0x0000, 0x0000 }, + { 0x10A5, 0x2D05, 0x0000, 0x0000 }, + { 0x1FAA, 0x1F62, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_182[] = { + { 0x01B7, 0x0292, 0x0000, 0x0000 }, + { 0x04B2, 0x04B3, 0x0000, 0x0000 }, + { 0x10A6, 0x2D06, 0x0000, 0x0000 }, + { 0x1EA8, 0x1EA9, 0x0000, 0x0000 }, + { 0x1FA9, 0x1F61, 0x03B9, 0x0000 }, + { 0x2C9A, 0x2C9B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_183[] = { + { 0x10A7, 0x2D07, 0x0000, 0x0000 }, + { 0x1FA8, 0x1F60, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_184[] = { + { 0x04BC, 0x04BD, 0x0000, 0x0000 }, + { 0x10A8, 0x2D08, 0x0000, 0x0000 }, + { 0x1EA6, 0x1EA7, 0x0000, 0x0000 }, + { 0x1FA7, 0x1F67, 0x03B9, 0x0000 }, + { 0x2C94, 0x2C95, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_185[] = { + { 0x01B8, 0x01B9, 0x0000, 0x0000 }, + { 0x10A9, 0x2D09, 0x0000, 0x0000 }, + { 0x1FA6, 0x1F66, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_186[] = { + { 0x04BE, 0x04BF, 0x0000, 0x0000 }, + { 0x10AA, 0x2D0A, 0x0000, 0x0000 }, + { 0x1EA4, 0x1EA5, 0x0000, 0x0000 }, + { 0x1FA5, 0x1F65, 0x03B9, 0x0000 }, + { 0x2C96, 0x2C97, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_187[] = { + { 0x10AB, 0x2D0B, 0x0000, 0x0000 }, + { 0x1FA4, 0x1F64, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_188[] = { + { 0x04B8, 0x04B9, 0x0000, 0x0000 }, + { 0x10AC, 0x2D0C, 0x0000, 0x0000 }, + { 0x1EA2, 0x1EA3, 0x0000, 0x0000 }, + { 0x1FA3, 0x1F63, 0x03B9, 0x0000 }, + { 0x2C90, 0x2C91, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_189[] = { + { 0x01BC, 0x01BD, 0x0000, 0x0000 }, + { 0x10AD, 0x2D0D, 0x0000, 0x0000 }, + { 0x1FA2, 0x1F62, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_190[] = { + { 0x04BA, 0x04BB, 0x0000, 0x0000 }, + { 0x10AE, 0x2D0E, 0x0000, 0x0000 }, + { 0x1EA0, 0x1EA1, 0x0000, 0x0000 }, + { 0x1FA1, 0x1F61, 0x03B9, 0x0000 }, + { 0x2C92, 0x2C93, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_191[] = { + { 0x10AF, 0x2D0F, 0x0000, 0x0000 }, + { 0x1FA0, 0x1F60, 0x03B9, 0x0000 } +}; + +static const CaseFoldMapping case_fold_192[] = { + { 0x00C0, 0x00E0, 0x0000, 0x0000 }, + { 0x1EDE, 0x1EDF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_193[] = { + { 0x00C1, 0x00E1, 0x0000, 0x0000 }, + { 0x03C2, 0x03C3, 0x0000, 0x0000 }, + { 0x04C5, 0x04C6, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_194[] = { + { 0x00C2, 0x00E2, 0x0000, 0x0000 }, + { 0x1EDC, 0x1EDD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_195[] = { + { 0x00C3, 0x00E3, 0x0000, 0x0000 }, + { 0x04C7, 0x04C8, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_196[] = { + { 0x00C4, 0x00E4, 0x0000, 0x0000 }, + { 0x01C5, 0x01C6, 0x0000, 0x0000 }, + { 0x1EDA, 0x1EDB, 0x0000, 0x0000 }, + { 0x1FDB, 0x1F77, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_197[] = { + { 0x00C5, 0x00E5, 0x0000, 0x0000 }, + { 0x01C4, 0x01C6, 0x0000, 0x0000 }, + { 0x04C1, 0x04C2, 0x0000, 0x0000 }, + { 0x1FDA, 0x1F76, 0x0000, 0x0000 }, + { 0xFF3A, 0xFF5A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_198[] = { + { 0x00C6, 0x00E6, 0x0000, 0x0000 }, + { 0x01C7, 0x01C9, 0x0000, 0x0000 }, + { 0x1ED8, 0x1ED9, 0x0000, 0x0000 }, + { 0x1FD9, 0x1FD1, 0x0000, 0x0000 }, + { 0xFF39, 0xFF59, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_199[] = { + { 0x00C7, 0x00E7, 0x0000, 0x0000 }, + { 0x04C3, 0x04C4, 0x0000, 0x0000 }, + { 0x1FD8, 0x1FD0, 0x0000, 0x0000 }, + { 0xFF38, 0xFF58, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_200[] = { + { 0x00C8, 0x00E8, 0x0000, 0x0000 }, + { 0x1ED6, 0x1ED7, 0x0000, 0x0000 }, + { 0x1FD7, 0x03B9, 0x0308, 0x0342 }, + { 0xFF37, 0xFF57, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_201[] = { + { 0x00C9, 0x00E9, 0x0000, 0x0000 }, + { 0x01C8, 0x01C9, 0x0000, 0x0000 }, + { 0x04CD, 0x04CE, 0x0000, 0x0000 }, + { 0x1FD6, 0x03B9, 0x0342, 0x0000 }, + { 0xFF36, 0xFF56, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_202[] = { + { 0x00CA, 0x00EA, 0x0000, 0x0000 }, + { 0x01CB, 0x01CC, 0x0000, 0x0000 }, + { 0x1ED4, 0x1ED5, 0x0000, 0x0000 }, + { 0xFF35, 0xFF55, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_203[] = { + { 0x00CB, 0x00EB, 0x0000, 0x0000 }, + { 0x01CA, 0x01CC, 0x0000, 0x0000 }, + { 0xFF34, 0xFF54, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_204[] = { + { 0x00CC, 0x00EC, 0x0000, 0x0000 }, + { 0x01CD, 0x01CE, 0x0000, 0x0000 }, + { 0x1ED2, 0x1ED3, 0x0000, 0x0000 }, + { 0x1FD3, 0x03B9, 0x0308, 0x0301 }, + { 0x2CE0, 0x2CE1, 0x0000, 0x0000 }, + { 0xFF33, 0xFF53, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_205[] = { + { 0x00CD, 0x00ED, 0x0000, 0x0000 }, + { 0x04C9, 0x04CA, 0x0000, 0x0000 }, + { 0x1FD2, 0x03B9, 0x0308, 0x0300 }, + { 0xFF32, 0xFF52, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_206[] = { + { 0x00CE, 0x00EE, 0x0000, 0x0000 }, + { 0x01CF, 0x01D0, 0x0000, 0x0000 }, + { 0x1ED0, 0x1ED1, 0x0000, 0x0000 }, + { 0x2CE2, 0x2CE3, 0x0000, 0x0000 }, + { 0xFF31, 0xFF51, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_207[] = { + { 0x00CF, 0x00EF, 0x0000, 0x0000 }, + { 0x04CB, 0x04CC, 0x0000, 0x0000 }, + { 0xFF30, 0xFF50, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_208[] = { + { 0x00D0, 0x00F0, 0x0000, 0x0000 }, + { 0x01D1, 0x01D2, 0x0000, 0x0000 }, + { 0x04D4, 0x04D5, 0x0000, 0x0000 }, + { 0x10C0, 0x2D20, 0x0000, 0x0000 }, + { 0x1ECE, 0x1ECF, 0x0000, 0x0000 }, + { 0xFF2F, 0xFF4F, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_209[] = { + { 0x00D1, 0x00F1, 0x0000, 0x0000 }, + { 0x10C1, 0x2D21, 0x0000, 0x0000 }, + { 0xFF2E, 0xFF4E, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_210[] = { + { 0x00D2, 0x00F2, 0x0000, 0x0000 }, + { 0x01D3, 0x01D4, 0x0000, 0x0000 }, + { 0x03D1, 0x03B8, 0x0000, 0x0000 }, + { 0x04D6, 0x04D7, 0x0000, 0x0000 }, + { 0x10C2, 0x2D22, 0x0000, 0x0000 }, + { 0x1ECC, 0x1ECD, 0x0000, 0x0000 }, + { 0xFF2D, 0xFF4D, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_211[] = { + { 0x00D3, 0x00F3, 0x0000, 0x0000 }, + { 0x03D0, 0x03B2, 0x0000, 0x0000 }, + { 0x10C3, 0x2D23, 0x0000, 0x0000 }, + { 0x1FCC, 0x03B7, 0x03B9, 0x0000 }, + { 0xFF2C, 0xFF4C, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_212[] = { + { 0x00D4, 0x00F4, 0x0000, 0x0000 }, + { 0x01D5, 0x01D6, 0x0000, 0x0000 }, + { 0x04D0, 0x04D1, 0x0000, 0x0000 }, + { 0x10C4, 0x2D24, 0x0000, 0x0000 }, + { 0x1ECA, 0x1ECB, 0x0000, 0x0000 }, + { 0x1FCB, 0x1F75, 0x0000, 0x0000 }, + { 0xFF2B, 0xFF4B, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_213[] = { + { 0x00D5, 0x00F5, 0x0000, 0x0000 }, + { 0x03D6, 0x03C0, 0x0000, 0x0000 }, + { 0x10C5, 0x2D25, 0x0000, 0x0000 }, + { 0x1FCA, 0x1F74, 0x0000, 0x0000 }, + { 0xFF2A, 0xFF4A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_214[] = { + { 0x00D6, 0x00F6, 0x0000, 0x0000 }, + { 0x01D7, 0x01D8, 0x0000, 0x0000 }, + { 0x03D5, 0x03C6, 0x0000, 0x0000 }, + { 0x04D2, 0x04D3, 0x0000, 0x0000 }, + { 0x1EC8, 0x1EC9, 0x0000, 0x0000 }, + { 0x1FC9, 0x1F73, 0x0000, 0x0000 }, + { 0xFF29, 0xFF49, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_215[] = { + { 0x1FC8, 0x1F72, 0x0000, 0x0000 }, + { 0xFF28, 0xFF48, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_216[] = { + { 0x00D8, 0x00F8, 0x0000, 0x0000 }, + { 0x01D9, 0x01DA, 0x0000, 0x0000 }, + { 0x04DC, 0x04DD, 0x0000, 0x0000 }, + { 0x1EC6, 0x1EC7, 0x0000, 0x0000 }, + { 0x1FC7, 0x03B7, 0x0342, 0x03B9 }, + { 0xFF27, 0xFF47, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_217[] = { + { 0x00D9, 0x00F9, 0x0000, 0x0000 }, + { 0x03DA, 0x03DB, 0x0000, 0x0000 }, + { 0x1FC6, 0x03B7, 0x0342, 0x0000 }, + { 0xFF26, 0xFF46, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_218[] = { + { 0x00DA, 0x00FA, 0x0000, 0x0000 }, + { 0x01DB, 0x01DC, 0x0000, 0x0000 }, + { 0x04DE, 0x04DF, 0x0000, 0x0000 }, + { 0x1EC4, 0x1EC5, 0x0000, 0x0000 }, + { 0xFF25, 0xFF45, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_219[] = { + { 0x00DB, 0x00FB, 0x0000, 0x0000 }, + { 0x03D8, 0x03D9, 0x0000, 0x0000 }, + { 0x1FC4, 0x03AE, 0x03B9, 0x0000 }, + { 0xFF24, 0xFF44, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_220[] = { + { 0x00DC, 0x00FC, 0x0000, 0x0000 }, + { 0x04D8, 0x04D9, 0x0000, 0x0000 }, + { 0x1EC2, 0x1EC3, 0x0000, 0x0000 }, + { 0x1FC3, 0x03B7, 0x03B9, 0x0000 }, + { 0xFF23, 0xFF43, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_221[] = { + { 0x00DD, 0x00FD, 0x0000, 0x0000 }, + { 0x03DE, 0x03DF, 0x0000, 0x0000 }, + { 0x1FC2, 0x1F74, 0x03B9, 0x0000 }, + { 0xFF22, 0xFF42, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_222[] = { + { 0x00DE, 0x00FE, 0x0000, 0x0000 }, + { 0x04DA, 0x04DB, 0x0000, 0x0000 }, + { 0x1EC0, 0x1EC1, 0x0000, 0x0000 }, + { 0xFF21, 0xFF41, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_223[] = { + { 0x00DF, 0x0073, 0x0073, 0x0000 }, + { 0x01DE, 0x01DF, 0x0000, 0x0000 }, + { 0x03DC, 0x03DD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_224[] = { + { 0x04E4, 0x04E5, 0x0000, 0x0000 }, + { 0x24C4, 0x24DE, 0x0000, 0x0000 }, + { 0x2CCC, 0x2CCD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_225[] = { + { 0x01E0, 0x01E1, 0x0000, 0x0000 }, + { 0x03E2, 0x03E3, 0x0000, 0x0000 }, + { 0x24C5, 0x24DF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_226[] = { + { 0x04E6, 0x04E7, 0x0000, 0x0000 }, + { 0x24C6, 0x24E0, 0x0000, 0x0000 }, + { 0x2CCE, 0x2CCF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_227[] = { + { 0x01E2, 0x01E3, 0x0000, 0x0000 }, + { 0x03E0, 0x03E1, 0x0000, 0x0000 }, + { 0x1FFC, 0x03C9, 0x03B9, 0x0000 }, + { 0x24C7, 0x24E1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_228[] = { + { 0x04E0, 0x04E1, 0x0000, 0x0000 }, + { 0x1FFB, 0x1F7D, 0x0000, 0x0000 }, + { 0x24C0, 0x24DA, 0x0000, 0x0000 }, + { 0x2CC8, 0x2CC9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_229[] = { + { 0x01E4, 0x01E5, 0x0000, 0x0000 }, + { 0x03E6, 0x03E7, 0x0000, 0x0000 }, + { 0x1FFA, 0x1F7C, 0x0000, 0x0000 }, + { 0x24C1, 0x24DB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_230[] = { + { 0x04E2, 0x04E3, 0x0000, 0x0000 }, + { 0x1EF8, 0x1EF9, 0x0000, 0x0000 }, + { 0x1FF9, 0x1F79, 0x0000, 0x0000 }, + { 0x24C2, 0x24DC, 0x0000, 0x0000 }, + { 0x2CCA, 0x2CCB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_231[] = { + { 0x01E6, 0x01E7, 0x0000, 0x0000 }, + { 0x03E4, 0x03E5, 0x0000, 0x0000 }, + { 0x1FF8, 0x1F78, 0x0000, 0x0000 }, + { 0x24C3, 0x24DD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_232[] = { + { 0x04EC, 0x04ED, 0x0000, 0x0000 }, + { 0x1EF6, 0x1EF7, 0x0000, 0x0000 }, + { 0x1FF7, 0x03C9, 0x0342, 0x03B9 }, + { 0x24CC, 0x24E6, 0x0000, 0x0000 }, + { 0x2CC4, 0x2CC5, 0x0000, 0x0000 }, + { 0xFB13, 0x0574, 0x0576, 0x0000 } +}; + +static const CaseFoldMapping case_fold_233[] = { + { 0x01E8, 0x01E9, 0x0000, 0x0000 }, + { 0x03EA, 0x03EB, 0x0000, 0x0000 }, + { 0x1FF6, 0x03C9, 0x0342, 0x0000 }, + { 0x24CD, 0x24E7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_234[] = { + { 0x04EE, 0x04EF, 0x0000, 0x0000 }, + { 0x1EF4, 0x1EF5, 0x0000, 0x0000 }, + { 0x24CE, 0x24E8, 0x0000, 0x0000 }, + { 0x2CC6, 0x2CC7, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_235[] = { + { 0x01EA, 0x01EB, 0x0000, 0x0000 }, + { 0x03E8, 0x03E9, 0x0000, 0x0000 }, + { 0x1FF4, 0x03CE, 0x03B9, 0x0000 }, + { 0x24CF, 0x24E9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_236[] = { + { 0x04E8, 0x04E9, 0x0000, 0x0000 }, + { 0x1EF2, 0x1EF3, 0x0000, 0x0000 }, + { 0x1FF3, 0x03C9, 0x03B9, 0x0000 }, + { 0x24C8, 0x24E2, 0x0000, 0x0000 }, + { 0x2CC0, 0x2CC1, 0x0000, 0x0000 }, + { 0xFB17, 0x0574, 0x056D, 0x0000 } +}; + +static const CaseFoldMapping case_fold_237[] = { + { 0x01EC, 0x01ED, 0x0000, 0x0000 }, + { 0x03EE, 0x03EF, 0x0000, 0x0000 }, + { 0x1FF2, 0x1F7C, 0x03B9, 0x0000 }, + { 0x24C9, 0x24E3, 0x0000, 0x0000 }, + { 0xFB16, 0x057E, 0x0576, 0x0000 } +}; + +static const CaseFoldMapping case_fold_238[] = { + { 0x04EA, 0x04EB, 0x0000, 0x0000 }, + { 0x1EF0, 0x1EF1, 0x0000, 0x0000 }, + { 0x24CA, 0x24E4, 0x0000, 0x0000 }, + { 0x2CC2, 0x2CC3, 0x0000, 0x0000 }, + { 0xFB15, 0x0574, 0x056B, 0x0000 } +}; + +static const CaseFoldMapping case_fold_239[] = { + { 0x01EE, 0x01EF, 0x0000, 0x0000 }, + { 0x03EC, 0x03ED, 0x0000, 0x0000 }, + { 0x24CB, 0x24E5, 0x0000, 0x0000 }, + { 0xFB14, 0x0574, 0x0565, 0x0000 } +}; + +static const CaseFoldMapping case_fold_240[] = { + { 0x01F1, 0x01F3, 0x0000, 0x0000 }, + { 0x04F4, 0x04F5, 0x0000, 0x0000 }, + { 0x1EEE, 0x1EEF, 0x0000, 0x0000 }, + { 0x2CDC, 0x2CDD, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_241[] = { + { 0x01F0, 0x006A, 0x030C, 0x0000 } +}; + +static const CaseFoldMapping case_fold_242[] = { + { 0x03F1, 0x03C1, 0x0000, 0x0000 }, + { 0x04F6, 0x04F7, 0x0000, 0x0000 }, + { 0x1EEC, 0x1EED, 0x0000, 0x0000 }, + { 0x2CDE, 0x2CDF, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_243[] = { + { 0x01F2, 0x01F3, 0x0000, 0x0000 }, + { 0x03F0, 0x03BA, 0x0000, 0x0000 }, + { 0x1FEC, 0x1FE5, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_244[] = { + { 0x03F7, 0x03F8, 0x0000, 0x0000 }, + { 0x04F0, 0x04F1, 0x0000, 0x0000 }, + { 0x1EEA, 0x1EEB, 0x0000, 0x0000 }, + { 0x1FEB, 0x1F7B, 0x0000, 0x0000 }, + { 0x2CD8, 0x2CD9, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_245[] = { + { 0x01F4, 0x01F5, 0x0000, 0x0000 }, + { 0x1FEA, 0x1F7A, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_246[] = { + { 0x01F7, 0x01BF, 0x0000, 0x0000 }, + { 0x03F5, 0x03B5, 0x0000, 0x0000 }, + { 0x04F2, 0x04F3, 0x0000, 0x0000 }, + { 0x1EE8, 0x1EE9, 0x0000, 0x0000 }, + { 0x1FE9, 0x1FE1, 0x0000, 0x0000 }, + { 0x2CDA, 0x2CDB, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_247[] = { + { 0x01F6, 0x0195, 0x0000, 0x0000 }, + { 0x03F4, 0x03B8, 0x0000, 0x0000 }, + { 0x1FE8, 0x1FE0, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_248[] = { + { 0x1EE6, 0x1EE7, 0x0000, 0x0000 }, + { 0x1FE7, 0x03C5, 0x0308, 0x0342 }, + { 0x2CD4, 0x2CD5, 0x0000, 0x0000 }, + { 0xFB03, 0x0066, 0x0066, 0x0069 } +}; + +static const CaseFoldMapping case_fold_249[] = { + { 0x01F8, 0x01F9, 0x0000, 0x0000 }, + { 0x03FA, 0x03FB, 0x0000, 0x0000 }, + { 0x1FE6, 0x03C5, 0x0342, 0x0000 }, + { 0xFB02, 0x0066, 0x006C, 0x0000 } +}; + +static const CaseFoldMapping case_fold_250[] = { + { 0x03F9, 0x03F2, 0x0000, 0x0000 }, + { 0x1EE4, 0x1EE5, 0x0000, 0x0000 }, + { 0x2CD6, 0x2CD7, 0x0000, 0x0000 }, + { 0xFB01, 0x0066, 0x0069, 0x0000 } +}; + +static const CaseFoldMapping case_fold_251[] = { + { 0x01FA, 0x01FB, 0x0000, 0x0000 }, + { 0x1FE4, 0x03C1, 0x0313, 0x0000 }, + { 0xFB00, 0x0066, 0x0066, 0x0000 } +}; + +static const CaseFoldMapping case_fold_252[] = { + { 0x04F8, 0x04F9, 0x0000, 0x0000 }, + { 0x1EE2, 0x1EE3, 0x0000, 0x0000 }, + { 0x1FE3, 0x03C5, 0x0308, 0x0301 }, + { 0x2CD0, 0x2CD1, 0x0000, 0x0000 } +}; + +static const CaseFoldMapping case_fold_253[] = { + { 0x01FC, 0x01FD, 0x0000, 0x0000 }, + { 0x1FE2, 0x03C5, 0x0308, 0x0300 }, + { 0xFB06, 0x0073, 0x0074, 0x0000 } +}; + +static const CaseFoldMapping case_fold_254[] = { + { 0x1EE0, 0x1EE1, 0x0000, 0x0000 }, + { 0x2CD2, 0x2CD3, 0x0000, 0x0000 }, + { 0xFB05, 0x0073, 0x0074, 0x0000 } +}; + +static const CaseFoldMapping case_fold_255[] = { + { 0x01FE, 0x01FF, 0x0000, 0x0000 }, + { 0xFB04, 0x0066, 0x0066, 0x006C } +}; + + +static const CaseFoldHashBucket case_fold_hash[256] = { + { __PHYSFS_ARRAYLEN(case_fold_000), case_fold_000 }, + { __PHYSFS_ARRAYLEN(case_fold_001), case_fold_001 }, + { __PHYSFS_ARRAYLEN(case_fold_002), case_fold_002 }, + { __PHYSFS_ARRAYLEN(case_fold_003), case_fold_003 }, + { __PHYSFS_ARRAYLEN(case_fold_004), case_fold_004 }, + { __PHYSFS_ARRAYLEN(case_fold_005), case_fold_005 }, + { __PHYSFS_ARRAYLEN(case_fold_006), case_fold_006 }, + { __PHYSFS_ARRAYLEN(case_fold_007), case_fold_007 }, + { __PHYSFS_ARRAYLEN(case_fold_008), case_fold_008 }, + { __PHYSFS_ARRAYLEN(case_fold_009), case_fold_009 }, + { __PHYSFS_ARRAYLEN(case_fold_010), case_fold_010 }, + { __PHYSFS_ARRAYLEN(case_fold_011), case_fold_011 }, + { __PHYSFS_ARRAYLEN(case_fold_012), case_fold_012 }, + { __PHYSFS_ARRAYLEN(case_fold_013), case_fold_013 }, + { __PHYSFS_ARRAYLEN(case_fold_014), case_fold_014 }, + { __PHYSFS_ARRAYLEN(case_fold_015), case_fold_015 }, + { __PHYSFS_ARRAYLEN(case_fold_016), case_fold_016 }, + { __PHYSFS_ARRAYLEN(case_fold_017), case_fold_017 }, + { __PHYSFS_ARRAYLEN(case_fold_018), case_fold_018 }, + { __PHYSFS_ARRAYLEN(case_fold_019), case_fold_019 }, + { __PHYSFS_ARRAYLEN(case_fold_020), case_fold_020 }, + { __PHYSFS_ARRAYLEN(case_fold_021), case_fold_021 }, + { __PHYSFS_ARRAYLEN(case_fold_022), case_fold_022 }, + { __PHYSFS_ARRAYLEN(case_fold_023), case_fold_023 }, + { __PHYSFS_ARRAYLEN(case_fold_024), case_fold_024 }, + { __PHYSFS_ARRAYLEN(case_fold_025), case_fold_025 }, + { __PHYSFS_ARRAYLEN(case_fold_026), case_fold_026 }, + { __PHYSFS_ARRAYLEN(case_fold_027), case_fold_027 }, + { __PHYSFS_ARRAYLEN(case_fold_028), case_fold_028 }, + { __PHYSFS_ARRAYLEN(case_fold_029), case_fold_029 }, + { __PHYSFS_ARRAYLEN(case_fold_030), case_fold_030 }, + { __PHYSFS_ARRAYLEN(case_fold_031), case_fold_031 }, + { __PHYSFS_ARRAYLEN(case_fold_032), case_fold_032 }, + { __PHYSFS_ARRAYLEN(case_fold_033), case_fold_033 }, + { __PHYSFS_ARRAYLEN(case_fold_034), case_fold_034 }, + { __PHYSFS_ARRAYLEN(case_fold_035), case_fold_035 }, + { __PHYSFS_ARRAYLEN(case_fold_036), case_fold_036 }, + { __PHYSFS_ARRAYLEN(case_fold_037), case_fold_037 }, + { __PHYSFS_ARRAYLEN(case_fold_038), case_fold_038 }, + { __PHYSFS_ARRAYLEN(case_fold_039), case_fold_039 }, + { __PHYSFS_ARRAYLEN(case_fold_040), case_fold_040 }, + { __PHYSFS_ARRAYLEN(case_fold_041), case_fold_041 }, + { __PHYSFS_ARRAYLEN(case_fold_042), case_fold_042 }, + { __PHYSFS_ARRAYLEN(case_fold_043), case_fold_043 }, + { __PHYSFS_ARRAYLEN(case_fold_044), case_fold_044 }, + { __PHYSFS_ARRAYLEN(case_fold_045), case_fold_045 }, + { __PHYSFS_ARRAYLEN(case_fold_046), case_fold_046 }, + { __PHYSFS_ARRAYLEN(case_fold_047), case_fold_047 }, + { __PHYSFS_ARRAYLEN(case_fold_048), case_fold_048 }, + { __PHYSFS_ARRAYLEN(case_fold_049), case_fold_049 }, + { __PHYSFS_ARRAYLEN(case_fold_050), case_fold_050 }, + { __PHYSFS_ARRAYLEN(case_fold_051), case_fold_051 }, + { __PHYSFS_ARRAYLEN(case_fold_052), case_fold_052 }, + { __PHYSFS_ARRAYLEN(case_fold_053), case_fold_053 }, + { __PHYSFS_ARRAYLEN(case_fold_054), case_fold_054 }, + { __PHYSFS_ARRAYLEN(case_fold_055), case_fold_055 }, + { __PHYSFS_ARRAYLEN(case_fold_056), case_fold_056 }, + { __PHYSFS_ARRAYLEN(case_fold_057), case_fold_057 }, + { __PHYSFS_ARRAYLEN(case_fold_058), case_fold_058 }, + { __PHYSFS_ARRAYLEN(case_fold_059), case_fold_059 }, + { __PHYSFS_ARRAYLEN(case_fold_060), case_fold_060 }, + { __PHYSFS_ARRAYLEN(case_fold_061), case_fold_061 }, + { __PHYSFS_ARRAYLEN(case_fold_062), case_fold_062 }, + { __PHYSFS_ARRAYLEN(case_fold_063), case_fold_063 }, + { __PHYSFS_ARRAYLEN(case_fold_064), case_fold_064 }, + { __PHYSFS_ARRAYLEN(case_fold_065), case_fold_065 }, + { __PHYSFS_ARRAYLEN(case_fold_066), case_fold_066 }, + { __PHYSFS_ARRAYLEN(case_fold_067), case_fold_067 }, + { __PHYSFS_ARRAYLEN(case_fold_068), case_fold_068 }, + { __PHYSFS_ARRAYLEN(case_fold_069), case_fold_069 }, + { __PHYSFS_ARRAYLEN(case_fold_070), case_fold_070 }, + { __PHYSFS_ARRAYLEN(case_fold_071), case_fold_071 }, + { __PHYSFS_ARRAYLEN(case_fold_072), case_fold_072 }, + { __PHYSFS_ARRAYLEN(case_fold_073), case_fold_073 }, + { __PHYSFS_ARRAYLEN(case_fold_074), case_fold_074 }, + { __PHYSFS_ARRAYLEN(case_fold_075), case_fold_075 }, + { __PHYSFS_ARRAYLEN(case_fold_076), case_fold_076 }, + { __PHYSFS_ARRAYLEN(case_fold_077), case_fold_077 }, + { __PHYSFS_ARRAYLEN(case_fold_078), case_fold_078 }, + { __PHYSFS_ARRAYLEN(case_fold_079), case_fold_079 }, + { __PHYSFS_ARRAYLEN(case_fold_080), case_fold_080 }, + { __PHYSFS_ARRAYLEN(case_fold_081), case_fold_081 }, + { __PHYSFS_ARRAYLEN(case_fold_082), case_fold_082 }, + { __PHYSFS_ARRAYLEN(case_fold_083), case_fold_083 }, + { __PHYSFS_ARRAYLEN(case_fold_084), case_fold_084 }, + { __PHYSFS_ARRAYLEN(case_fold_085), case_fold_085 }, + { __PHYSFS_ARRAYLEN(case_fold_086), case_fold_086 }, + { __PHYSFS_ARRAYLEN(case_fold_087), case_fold_087 }, + { __PHYSFS_ARRAYLEN(case_fold_088), case_fold_088 }, + { __PHYSFS_ARRAYLEN(case_fold_089), case_fold_089 }, + { __PHYSFS_ARRAYLEN(case_fold_090), case_fold_090 }, + { __PHYSFS_ARRAYLEN(case_fold_091), case_fold_091 }, + { __PHYSFS_ARRAYLEN(case_fold_092), case_fold_092 }, + { __PHYSFS_ARRAYLEN(case_fold_093), case_fold_093 }, + { __PHYSFS_ARRAYLEN(case_fold_094), case_fold_094 }, + { __PHYSFS_ARRAYLEN(case_fold_095), case_fold_095 }, + { __PHYSFS_ARRAYLEN(case_fold_096), case_fold_096 }, + { __PHYSFS_ARRAYLEN(case_fold_097), case_fold_097 }, + { __PHYSFS_ARRAYLEN(case_fold_098), case_fold_098 }, + { __PHYSFS_ARRAYLEN(case_fold_099), case_fold_099 }, + { __PHYSFS_ARRAYLEN(case_fold_100), case_fold_100 }, + { __PHYSFS_ARRAYLEN(case_fold_101), case_fold_101 }, + { __PHYSFS_ARRAYLEN(case_fold_102), case_fold_102 }, + { __PHYSFS_ARRAYLEN(case_fold_103), case_fold_103 }, + { __PHYSFS_ARRAYLEN(case_fold_104), case_fold_104 }, + { __PHYSFS_ARRAYLEN(case_fold_105), case_fold_105 }, + { __PHYSFS_ARRAYLEN(case_fold_106), case_fold_106 }, + { __PHYSFS_ARRAYLEN(case_fold_107), case_fold_107 }, + { __PHYSFS_ARRAYLEN(case_fold_108), case_fold_108 }, + { __PHYSFS_ARRAYLEN(case_fold_109), case_fold_109 }, + { __PHYSFS_ARRAYLEN(case_fold_110), case_fold_110 }, + { __PHYSFS_ARRAYLEN(case_fold_111), case_fold_111 }, + { __PHYSFS_ARRAYLEN(case_fold_112), case_fold_112 }, + { __PHYSFS_ARRAYLEN(case_fold_113), case_fold_113 }, + { __PHYSFS_ARRAYLEN(case_fold_114), case_fold_114 }, + { __PHYSFS_ARRAYLEN(case_fold_115), case_fold_115 }, + { __PHYSFS_ARRAYLEN(case_fold_116), case_fold_116 }, + { __PHYSFS_ARRAYLEN(case_fold_117), case_fold_117 }, + { __PHYSFS_ARRAYLEN(case_fold_118), case_fold_118 }, + { __PHYSFS_ARRAYLEN(case_fold_119), case_fold_119 }, + { __PHYSFS_ARRAYLEN(case_fold_120), case_fold_120 }, + { __PHYSFS_ARRAYLEN(case_fold_121), case_fold_121 }, + { __PHYSFS_ARRAYLEN(case_fold_122), case_fold_122 }, + { 0, NULL }, + { __PHYSFS_ARRAYLEN(case_fold_124), case_fold_124 }, + { 0, NULL }, + { __PHYSFS_ARRAYLEN(case_fold_126), case_fold_126 }, + { 0, NULL }, + { __PHYSFS_ARRAYLEN(case_fold_128), case_fold_128 }, + { __PHYSFS_ARRAYLEN(case_fold_129), case_fold_129 }, + { __PHYSFS_ARRAYLEN(case_fold_130), case_fold_130 }, + { __PHYSFS_ARRAYLEN(case_fold_131), case_fold_131 }, + { __PHYSFS_ARRAYLEN(case_fold_132), case_fold_132 }, + { __PHYSFS_ARRAYLEN(case_fold_133), case_fold_133 }, + { __PHYSFS_ARRAYLEN(case_fold_134), case_fold_134 }, + { __PHYSFS_ARRAYLEN(case_fold_135), case_fold_135 }, + { __PHYSFS_ARRAYLEN(case_fold_136), case_fold_136 }, + { __PHYSFS_ARRAYLEN(case_fold_137), case_fold_137 }, + { __PHYSFS_ARRAYLEN(case_fold_138), case_fold_138 }, + { __PHYSFS_ARRAYLEN(case_fold_139), case_fold_139 }, + { __PHYSFS_ARRAYLEN(case_fold_140), case_fold_140 }, + { __PHYSFS_ARRAYLEN(case_fold_141), case_fold_141 }, + { __PHYSFS_ARRAYLEN(case_fold_142), case_fold_142 }, + { __PHYSFS_ARRAYLEN(case_fold_143), case_fold_143 }, + { __PHYSFS_ARRAYLEN(case_fold_144), case_fold_144 }, + { __PHYSFS_ARRAYLEN(case_fold_145), case_fold_145 }, + { __PHYSFS_ARRAYLEN(case_fold_146), case_fold_146 }, + { __PHYSFS_ARRAYLEN(case_fold_147), case_fold_147 }, + { __PHYSFS_ARRAYLEN(case_fold_148), case_fold_148 }, + { __PHYSFS_ARRAYLEN(case_fold_149), case_fold_149 }, + { __PHYSFS_ARRAYLEN(case_fold_150), case_fold_150 }, + { __PHYSFS_ARRAYLEN(case_fold_151), case_fold_151 }, + { __PHYSFS_ARRAYLEN(case_fold_152), case_fold_152 }, + { __PHYSFS_ARRAYLEN(case_fold_153), case_fold_153 }, + { __PHYSFS_ARRAYLEN(case_fold_154), case_fold_154 }, + { __PHYSFS_ARRAYLEN(case_fold_155), case_fold_155 }, + { __PHYSFS_ARRAYLEN(case_fold_156), case_fold_156 }, + { __PHYSFS_ARRAYLEN(case_fold_157), case_fold_157 }, + { __PHYSFS_ARRAYLEN(case_fold_158), case_fold_158 }, + { __PHYSFS_ARRAYLEN(case_fold_159), case_fold_159 }, + { __PHYSFS_ARRAYLEN(case_fold_160), case_fold_160 }, + { __PHYSFS_ARRAYLEN(case_fold_161), case_fold_161 }, + { __PHYSFS_ARRAYLEN(case_fold_162), case_fold_162 }, + { __PHYSFS_ARRAYLEN(case_fold_163), case_fold_163 }, + { __PHYSFS_ARRAYLEN(case_fold_164), case_fold_164 }, + { __PHYSFS_ARRAYLEN(case_fold_165), case_fold_165 }, + { __PHYSFS_ARRAYLEN(case_fold_166), case_fold_166 }, + { __PHYSFS_ARRAYLEN(case_fold_167), case_fold_167 }, + { __PHYSFS_ARRAYLEN(case_fold_168), case_fold_168 }, + { __PHYSFS_ARRAYLEN(case_fold_169), case_fold_169 }, + { __PHYSFS_ARRAYLEN(case_fold_170), case_fold_170 }, + { __PHYSFS_ARRAYLEN(case_fold_171), case_fold_171 }, + { __PHYSFS_ARRAYLEN(case_fold_172), case_fold_172 }, + { __PHYSFS_ARRAYLEN(case_fold_173), case_fold_173 }, + { __PHYSFS_ARRAYLEN(case_fold_174), case_fold_174 }, + { __PHYSFS_ARRAYLEN(case_fold_175), case_fold_175 }, + { __PHYSFS_ARRAYLEN(case_fold_176), case_fold_176 }, + { __PHYSFS_ARRAYLEN(case_fold_177), case_fold_177 }, + { __PHYSFS_ARRAYLEN(case_fold_178), case_fold_178 }, + { __PHYSFS_ARRAYLEN(case_fold_179), case_fold_179 }, + { __PHYSFS_ARRAYLEN(case_fold_180), case_fold_180 }, + { __PHYSFS_ARRAYLEN(case_fold_181), case_fold_181 }, + { __PHYSFS_ARRAYLEN(case_fold_182), case_fold_182 }, + { __PHYSFS_ARRAYLEN(case_fold_183), case_fold_183 }, + { __PHYSFS_ARRAYLEN(case_fold_184), case_fold_184 }, + { __PHYSFS_ARRAYLEN(case_fold_185), case_fold_185 }, + { __PHYSFS_ARRAYLEN(case_fold_186), case_fold_186 }, + { __PHYSFS_ARRAYLEN(case_fold_187), case_fold_187 }, + { __PHYSFS_ARRAYLEN(case_fold_188), case_fold_188 }, + { __PHYSFS_ARRAYLEN(case_fold_189), case_fold_189 }, + { __PHYSFS_ARRAYLEN(case_fold_190), case_fold_190 }, + { __PHYSFS_ARRAYLEN(case_fold_191), case_fold_191 }, + { __PHYSFS_ARRAYLEN(case_fold_192), case_fold_192 }, + { __PHYSFS_ARRAYLEN(case_fold_193), case_fold_193 }, + { __PHYSFS_ARRAYLEN(case_fold_194), case_fold_194 }, + { __PHYSFS_ARRAYLEN(case_fold_195), case_fold_195 }, + { __PHYSFS_ARRAYLEN(case_fold_196), case_fold_196 }, + { __PHYSFS_ARRAYLEN(case_fold_197), case_fold_197 }, + { __PHYSFS_ARRAYLEN(case_fold_198), case_fold_198 }, + { __PHYSFS_ARRAYLEN(case_fold_199), case_fold_199 }, + { __PHYSFS_ARRAYLEN(case_fold_200), case_fold_200 }, + { __PHYSFS_ARRAYLEN(case_fold_201), case_fold_201 }, + { __PHYSFS_ARRAYLEN(case_fold_202), case_fold_202 }, + { __PHYSFS_ARRAYLEN(case_fold_203), case_fold_203 }, + { __PHYSFS_ARRAYLEN(case_fold_204), case_fold_204 }, + { __PHYSFS_ARRAYLEN(case_fold_205), case_fold_205 }, + { __PHYSFS_ARRAYLEN(case_fold_206), case_fold_206 }, + { __PHYSFS_ARRAYLEN(case_fold_207), case_fold_207 }, + { __PHYSFS_ARRAYLEN(case_fold_208), case_fold_208 }, + { __PHYSFS_ARRAYLEN(case_fold_209), case_fold_209 }, + { __PHYSFS_ARRAYLEN(case_fold_210), case_fold_210 }, + { __PHYSFS_ARRAYLEN(case_fold_211), case_fold_211 }, + { __PHYSFS_ARRAYLEN(case_fold_212), case_fold_212 }, + { __PHYSFS_ARRAYLEN(case_fold_213), case_fold_213 }, + { __PHYSFS_ARRAYLEN(case_fold_214), case_fold_214 }, + { __PHYSFS_ARRAYLEN(case_fold_215), case_fold_215 }, + { __PHYSFS_ARRAYLEN(case_fold_216), case_fold_216 }, + { __PHYSFS_ARRAYLEN(case_fold_217), case_fold_217 }, + { __PHYSFS_ARRAYLEN(case_fold_218), case_fold_218 }, + { __PHYSFS_ARRAYLEN(case_fold_219), case_fold_219 }, + { __PHYSFS_ARRAYLEN(case_fold_220), case_fold_220 }, + { __PHYSFS_ARRAYLEN(case_fold_221), case_fold_221 }, + { __PHYSFS_ARRAYLEN(case_fold_222), case_fold_222 }, + { __PHYSFS_ARRAYLEN(case_fold_223), case_fold_223 }, + { __PHYSFS_ARRAYLEN(case_fold_224), case_fold_224 }, + { __PHYSFS_ARRAYLEN(case_fold_225), case_fold_225 }, + { __PHYSFS_ARRAYLEN(case_fold_226), case_fold_226 }, + { __PHYSFS_ARRAYLEN(case_fold_227), case_fold_227 }, + { __PHYSFS_ARRAYLEN(case_fold_228), case_fold_228 }, + { __PHYSFS_ARRAYLEN(case_fold_229), case_fold_229 }, + { __PHYSFS_ARRAYLEN(case_fold_230), case_fold_230 }, + { __PHYSFS_ARRAYLEN(case_fold_231), case_fold_231 }, + { __PHYSFS_ARRAYLEN(case_fold_232), case_fold_232 }, + { __PHYSFS_ARRAYLEN(case_fold_233), case_fold_233 }, + { __PHYSFS_ARRAYLEN(case_fold_234), case_fold_234 }, + { __PHYSFS_ARRAYLEN(case_fold_235), case_fold_235 }, + { __PHYSFS_ARRAYLEN(case_fold_236), case_fold_236 }, + { __PHYSFS_ARRAYLEN(case_fold_237), case_fold_237 }, + { __PHYSFS_ARRAYLEN(case_fold_238), case_fold_238 }, + { __PHYSFS_ARRAYLEN(case_fold_239), case_fold_239 }, + { __PHYSFS_ARRAYLEN(case_fold_240), case_fold_240 }, + { __PHYSFS_ARRAYLEN(case_fold_241), case_fold_241 }, + { __PHYSFS_ARRAYLEN(case_fold_242), case_fold_242 }, + { __PHYSFS_ARRAYLEN(case_fold_243), case_fold_243 }, + { __PHYSFS_ARRAYLEN(case_fold_244), case_fold_244 }, + { __PHYSFS_ARRAYLEN(case_fold_245), case_fold_245 }, + { __PHYSFS_ARRAYLEN(case_fold_246), case_fold_246 }, + { __PHYSFS_ARRAYLEN(case_fold_247), case_fold_247 }, + { __PHYSFS_ARRAYLEN(case_fold_248), case_fold_248 }, + { __PHYSFS_ARRAYLEN(case_fold_249), case_fold_249 }, + { __PHYSFS_ARRAYLEN(case_fold_250), case_fold_250 }, + { __PHYSFS_ARRAYLEN(case_fold_251), case_fold_251 }, + { __PHYSFS_ARRAYLEN(case_fold_252), case_fold_252 }, + { __PHYSFS_ARRAYLEN(case_fold_253), case_fold_253 }, + { __PHYSFS_ARRAYLEN(case_fold_254), case_fold_254 }, + { __PHYSFS_ARRAYLEN(case_fold_255), case_fold_255 }, +}; + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_internal.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_internal.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,776 @@ +/* + * Internal function/structure declaration. Do NOT include in your + * application. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#ifndef _INCLUDE_PHYSFS_INTERNAL_H_ +#define _INCLUDE_PHYSFS_INTERNAL_H_ + +#ifndef __PHYSICSFS_INTERNAL__ +#error Do not include this header from your applications. +#endif + +#include "physfs.h" + +/* The holy trinity. */ +#include +#include +#include + +#include "physfs_platforms.h" + +#include + +/* !!! FIXME: remove this when revamping stack allocation code... */ +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#endif + +#if PHYSFS_PLATFORM_SOLARIS +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __GNUC__ +#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) \ + ( ((__GNUC__ << 16) + __GNUC_MINOR__) >= (((major) << 16) + (minor)) ) +#else +#define PHYSFS_MINIMUM_GCC_VERSION(major, minor) (0) +#endif + +#ifdef __cplusplus + /* C++ always has a real inline keyword. */ +#elif (defined macintosh) && !(defined __MWERKS__) +# define inline +#elif (defined _MSC_VER) +# define inline __inline +#endif + +#if PHYSFS_PLATFORM_LINUX && !defined(_FILE_OFFSET_BITS) +#define _FILE_OFFSET_BITS 64 +#endif + +/* + * Interface for small allocations. If you need a little scratch space for + * a throwaway buffer or string, use this. It will make small allocations + * on the stack if possible, and use allocator.Malloc() if they are too + * large. This helps reduce malloc pressure. + * There are some rules, though: + * NEVER return a pointer from this, as stack-allocated buffers go away + * when your function returns. + * NEVER allocate in a loop, as stack-allocated pointers will pile up. Call + * a function that uses smallAlloc from your loop, so the allocation can + * free each time. + * NEVER call smallAlloc with any complex expression (it's a macro that WILL + * have side effects...it references the argument multiple times). Use a + * variable or a literal. + * NEVER free a pointer from this with anything but smallFree. It will not + * be a valid pointer to the allocator, regardless of where the memory came + * from. + * NEVER realloc a pointer from this. + * NEVER forget to use smallFree: it may not be a pointer from the stack. + * NEVER forget to check for NULL...allocation can fail here, of course! + */ +#define __PHYSFS_SMALLALLOCTHRESHOLD 256 +void *__PHYSFS_initSmallAlloc(void *ptr, PHYSFS_uint64 len); + +#define __PHYSFS_smallAlloc(bytes) ( \ + __PHYSFS_initSmallAlloc( \ + (((bytes) < __PHYSFS_SMALLALLOCTHRESHOLD) ? \ + alloca((size_t)((bytes)+sizeof(void*))) : NULL), (bytes)) \ +) + +void __PHYSFS_smallFree(void *ptr); + + +/* Use the allocation hooks. */ +#define malloc(x) Do not use malloc() directly. +#define realloc(x, y) Do not use realloc() directly. +#define free(x) Do not use free() directly. +/* !!! FIXME: add alloca check here. */ + +#ifndef PHYSFS_SUPPORTS_ZIP +#define PHYSFS_SUPPORTS_ZIP 1 +#endif +#ifndef PHYSFS_SUPPORTS_7Z +#define PHYSFS_SUPPORTS_7Z 0 +#endif +#ifndef PHYSFS_SUPPORTS_GRP +#define PHYSFS_SUPPORTS_GRP 0 +#endif +#ifndef PHYSFS_SUPPORTS_HOG +#define PHYSFS_SUPPORTS_HOG 0 +#endif +#ifndef PHYSFS_SUPPORTS_MVL +#define PHYSFS_SUPPORTS_MVL 0 +#endif +#ifndef PHYSFS_SUPPORTS_WAD +#define PHYSFS_SUPPORTS_WAD 0 +#endif +#ifndef PHYSFS_SUPPORTS_ISO9660 +#define PHYSFS_SUPPORTS_ISO9660 0 +#endif + +/* The latest supported PHYSFS_Io::version value. */ +#define CURRENT_PHYSFS_IO_API_VERSION 0 + +/* Opaque data for file and dir handlers... */ +typedef void PHYSFS_Dir; + +typedef struct +{ + /* + * Basic info about this archiver... + */ + const PHYSFS_ArchiveInfo info; + + + /* + * DIRECTORY ROUTINES: + * These functions are for dir handles. Generate a handle with the + * openArchive() method, then pass it as the "opaque" PHYSFS_Dir to the + * others. + * + * Symlinks should always be followed (except in stat()); PhysicsFS will + * use the stat() method to check for symlinks and make a judgement on + * whether to continue to call other methods based on that. + */ + + /* + * Open a dirhandle for dir/archive data provided by (io). + * (name) is a filename associated with (io), but doesn't necessarily + * map to anything, let alone a real filename. This possibly- + * meaningless name is in platform-dependent notation. + * (forWrite) is non-zero if this is to be used for + * the write directory, and zero if this is to be used for an + * element of the search path. + * Returns NULL on failure. We ignore any error code you set here. + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later calls. + */ + PHYSFS_Dir *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite); + + /* + * List all files in (dirname). Each file is passed to (cb), + * where a copy is made if appropriate, so you should dispose of + * it properly upon return from the callback. + * You should omit symlinks if (omitSymLinks) is non-zero. + * If you have a failure, report as much as you can. + * (dirname) is in platform-independent notation. + */ + void (*enumerateFiles)(PHYSFS_Dir *opaque, const char *dirname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata); + + /* + * Open file for reading. + * This filename, (fnm), is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Fail if the file does not exist. + * Returns NULL on failure, and calls __PHYSFS_setError(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + * + * Regardless of success or failure, please set *exists to + * non-zero if the file existed (even if it's a broken symlink!), + * zero if it did not. + */ + PHYSFS_Io *(*openRead)(PHYSFS_Dir *opaque, const char *fnm, int *exists); + + /* + * Open file for writing. + * If the file does not exist, it should be created. If it exists, + * it should be truncated to zero bytes. The writing + * offset should be the start of the file. + * This filename is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Returns NULL on failure, and calls __PHYSFS_setError(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + */ + PHYSFS_Io *(*openWrite)(PHYSFS_Dir *opaque, const char *filename); + + /* + * Open file for appending. + * If the file does not exist, it should be created. The writing + * offset should be the end of the file. + * This filename is in platform-independent notation. + * If you can't handle multiple opens of the same file, + * you can opt to fail for the second call. + * Returns NULL on failure, and calls __PHYSFS_setError(). + * Returns non-NULL on success. The pointer returned will be + * passed as the "opaque" parameter for later file calls. + */ + PHYSFS_Io *(*openAppend)(PHYSFS_Dir *opaque, const char *filename); + + /* + * Delete a file in the archive/directory. + * Return non-zero on success, zero on failure. + * This filename is in platform-independent notation. + * This method may be NULL. + * On failure, call __PHYSFS_setError(). + */ + int (*remove)(PHYSFS_Dir *opaque, const char *filename); + + /* + * Create a directory in the archive/directory. + * If the application is trying to make multiple dirs, PhysicsFS + * will split them up into multiple calls before passing them to + * your driver. + * Return non-zero on success, zero on failure. + * This filename is in platform-independent notation. + * This method may be NULL. + * On failure, call __PHYSFS_setError(). + */ + int (*mkdir)(PHYSFS_Dir *opaque, const char *filename); + + /* + * Close directories/archives, and free any associated memory, + * including the original PHYSFS_Io and (opaque) itself, if + * applicable. Implementation can assume that it won't be called if + * there are still files open from this archive. + */ + void (*closeArchive)(PHYSFS_Dir *opaque); + + /* + * Obtain basic file metadata. + * Returns non-zero on success, zero on failure. + * On failure, call __PHYSFS_setError(). + */ + int (*stat)(PHYSFS_Dir *opaque, const char *fn, + int *exists, PHYSFS_Stat *stat); +} PHYSFS_Archiver; + + +/* + * Call this to set the message returned by PHYSFS_getLastError(). + * Please only use the ERR_* constants above, or add new constants to the + * above group, but I want these all in one place. + * + * Calling this with a NULL argument is a safe no-op. + */ +void __PHYSFS_setError(const PHYSFS_ErrorCode err); + + +/* This byteorder stuff was lifted from SDL. http://www.libsdl.org/ */ +#define PHYSFS_LIL_ENDIAN 1234 +#define PHYSFS_BIG_ENDIAN 4321 + +#if defined(__i386__) || defined(__ia64__) || \ + defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64) || \ + (defined(__alpha__) || defined(__alpha)) || \ + defined(__arm__) || defined(ARM) || \ + (defined(__mips__) && defined(__MIPSEL__)) || \ + defined(__SYMBIAN32__) || \ + defined(__x86_64__) || \ + defined(__LITTLE_ENDIAN__) +#define PHYSFS_BYTEORDER PHYSFS_LIL_ENDIAN +#else +#define PHYSFS_BYTEORDER PHYSFS_BIG_ENDIAN +#endif + + +/* + * When sorting the entries in an archive, we use a modified QuickSort. + * When there are less then PHYSFS_QUICKSORT_THRESHOLD entries left to sort, + * we switch over to a BubbleSort for the remainder. Tweak to taste. + * + * You can override this setting by defining PHYSFS_QUICKSORT_THRESHOLD + * before #including "physfs_internal.h". + */ +#ifndef PHYSFS_QUICKSORT_THRESHOLD +#define PHYSFS_QUICKSORT_THRESHOLD 4 +#endif + +/* + * Sort an array (or whatever) of (max) elements. This uses a mixture of + * a QuickSort and BubbleSort internally. + * (cmpfn) is used to determine ordering, and (swapfn) does the actual + * swapping of elements in the list. + * + * See zip.c for an example. + */ +void __PHYSFS_sort(void *entries, size_t max, + int (*cmpfn)(void *, size_t, size_t), + void (*swapfn)(void *, size_t, size_t)); + +/* + * This isn't a formal error code, it's just for BAIL_MACRO. + * It means: there was an error, but someone else already set it for us. + */ +#define ERRPASS PHYSFS_ERR_OK + +/* These get used all over for lessening code clutter. */ +#define BAIL_MACRO(e, r) do { if (e) __PHYSFS_setError(e); return r; } while (0) +#define BAIL_IF_MACRO(c, e, r) do { if (c) { if (e) __PHYSFS_setError(e); return r; } } while (0) +#define BAIL_MACRO_MUTEX(e, m, r) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } while (0) +#define BAIL_IF_MACRO_MUTEX(c, e, m, r) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); return r; } } while (0) +#define GOTO_MACRO(e, g) do { if (e) __PHYSFS_setError(e); goto g; } while (0) +#define GOTO_IF_MACRO(c, e, g) do { if (c) { if (e) __PHYSFS_setError(e); goto g; } } while (0) +#define GOTO_MACRO_MUTEX(e, m, g) do { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } while (0) +#define GOTO_IF_MACRO_MUTEX(c, e, m, g) do { if (c) { if (e) __PHYSFS_setError(e); __PHYSFS_platformReleaseMutex(m); goto g; } } while (0) + +#define __PHYSFS_ARRAYLEN(x) ( (sizeof (x)) / (sizeof (x[0])) ) + +#ifdef PHYSFS_NO_64BIT_SUPPORT +#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x)) +#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x)) +#elif (defined __GNUC__) +#define __PHYSFS_SI64(x) x##LL +#define __PHYSFS_UI64(x) x##ULL +#elif (defined _MSC_VER) +#define __PHYSFS_SI64(x) x##i64 +#define __PHYSFS_UI64(x) x##ui64 +#else +#define __PHYSFS_SI64(x) ((PHYSFS_sint64) (x)) +#define __PHYSFS_UI64(x) ((PHYSFS_uint64) (x)) +#endif + + +/* + * Check if a ui64 will fit in the platform's address space. + * The initial sizeof check will optimize this macro out entirely on + * 64-bit (and larger?!) platforms, and the other condition will + * return zero or non-zero if the variable will fit in the platform's + * size_t, suitable to pass to malloc. This is kinda messy, but effective. + */ +#define __PHYSFS_ui64FitsAddressSpace(s) ( \ + (sizeof (PHYSFS_uint64) <= sizeof (size_t)) || \ + ((s) < (__PHYSFS_UI64(0xFFFFFFFFFFFFFFFF) >> (64-(sizeof(size_t)*8)))) \ +) + + +/* + * This is a strcasecmp() or stricmp() replacement that expects both strings + * to be in UTF-8 encoding. It will do "case folding" to decide if the + * Unicode codepoints in the strings match. + * + * It will report which string is "greater than" the other, but be aware that + * this doesn't necessarily mean anything: 'a' may be "less than" 'b', but + * a random Kanji codepoint has no meaningful alphabetically relationship to + * a Greek Lambda, but being able to assign a reliable "value" makes sorting + * algorithms possible, if not entirely sane. Most cases should treat the + * return value as "equal" or "not equal". + */ +int __PHYSFS_utf8stricmp(const char *s1, const char *s2); + +/* + * This works like __PHYSFS_utf8stricmp(), but takes a character (NOT BYTE + * COUNT) argument, like strcasencmp(). + */ +int __PHYSFS_utf8strnicmp(const char *s1, const char *s2, PHYSFS_uint32 l); + +/* + * stricmp() that guarantees to only work with low ASCII. The C runtime + * stricmp() might try to apply a locale/codepage/etc, which we don't want. + */ +int __PHYSFS_stricmpASCII(const char *s1, const char *s2); + +/* + * strnicmp() that guarantees to only work with low ASCII. The C runtime + * strnicmp() might try to apply a locale/codepage/etc, which we don't want. + */ +int __PHYSFS_strnicmpASCII(const char *s1, const char *s2, PHYSFS_uint32 l); + + +/* + * The current allocator. Not valid before PHYSFS_init is called! + */ +extern PHYSFS_Allocator __PHYSFS_AllocatorHooks; + +/* convenience macro to make this less cumbersome internally... */ +#define allocator __PHYSFS_AllocatorHooks + +/* + * Create a PHYSFS_Io for a file in the physical filesystem. + * This path is in platform-dependent notation. (mode) must be 'r', 'w', or + * 'a' for Read, Write, or Append. + */ +PHYSFS_Io *__PHYSFS_createNativeIo(const char *path, const int mode); + +/* + * Create a PHYSFS_Io for a buffer of memory (READ-ONLY). If you already + * have one of these, just use its duplicate() method, and it'll increment + * its refcount without allocating a copy of the buffer. + */ +PHYSFS_Io *__PHYSFS_createMemoryIo(const void *buf, PHYSFS_uint64 len, + void (*destruct)(void *)); + + +/* + * Read (len) bytes from (io) into (buf). Returns non-zero on success, + * zero on i/o error. Literally: "return (io->read(io, buf, len) == len);" + */ +int __PHYSFS_readAll(PHYSFS_Io *io, void *buf, const PHYSFS_uint64 len); + + +/* These are shared between some archivers. */ + +typedef struct +{ + char name[56]; + PHYSFS_uint32 startPos; + PHYSFS_uint32 size; +} UNPKentry; + +void UNPK_closeArchive(PHYSFS_Dir *opaque); +PHYSFS_Dir *UNPK_openArchive(PHYSFS_Io *io,UNPKentry *e,const PHYSFS_uint32 n); +void UNPK_enumerateFiles(PHYSFS_Dir *opaque, const char *dname, + int omitSymLinks, PHYSFS_EnumFilesCallback cb, + const char *origdir, void *callbackdata); +PHYSFS_Io *UNPK_openRead(PHYSFS_Dir *opaque, const char *fnm, int *fileExists); +PHYSFS_Io *UNPK_openWrite(PHYSFS_Dir *opaque, const char *name); +PHYSFS_Io *UNPK_openAppend(PHYSFS_Dir *opaque, const char *name); +int UNPK_remove(PHYSFS_Dir *opaque, const char *name); +int UNPK_mkdir(PHYSFS_Dir *opaque, const char *name); +int UNPK_stat(PHYSFS_Dir *opaque, const char *fn, int *exist, PHYSFS_Stat *st); + + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +/*------------ ----------------*/ +/*------------ You MUST implement the following functions ----------------*/ +/*------------ if porting to a new platform. ----------------*/ +/*------------ (see platform/unix.c for an example) ----------------*/ +/*------------ ----------------*/ +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ + + +/* + * The dir separator; '/' on unix, '\\' on win32, ":" on MacOS, etc... + * Obviously, this isn't a function. If you need more than one char for this, + * you'll need to pull some old pieces of PhysicsFS out of revision control. + */ +#if PHYSFS_PLATFORM_WINDOWS +#define __PHYSFS_platformDirSeparator '\\' +#else +#define __PHYSFS_platformDirSeparator '/' +#endif + +/* + * Initialize the platform. This is called when PHYSFS_init() is called from + * the application. + * + * Return zero if there was a catastrophic failure (which prevents you from + * functioning at all), and non-zero otherwise. + */ +int __PHYSFS_platformInit(void); + + +/* + * Deinitialize the platform. This is called when PHYSFS_deinit() is called + * from the application. You can use this to clean up anything you've + * allocated in your platform driver. + * + * Return zero if there was a catastrophic failure (which prevents you from + * functioning at all), and non-zero otherwise. + */ +int __PHYSFS_platformDeinit(void); + + +/* + * Open a file for reading. (filename) is in platform-dependent notation. The + * file pointer should be positioned on the first byte of the file. + * + * The return value will be some platform-specific datatype that is opaque to + * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32. + * + * The same file can be opened for read multiple times, and each should have + * a unique file handle; this is frequently employed to prevent race + * conditions in the archivers. + * + * Call __PHYSFS_setError() and return (NULL) if the file can't be opened. + */ +void *__PHYSFS_platformOpenRead(const char *filename); + + +/* + * Open a file for writing. (filename) is in platform-dependent notation. If + * the file exists, it should be truncated to zero bytes, and if it doesn't + * exist, it should be created as a zero-byte file. The file pointer should + * be positioned on the first byte of the file. + * + * The return value will be some platform-specific datatype that is opaque to + * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32, + * etc. + * + * Opening a file for write multiple times has undefined results. + * + * Call __PHYSFS_setError() and return (NULL) if the file can't be opened. + */ +void *__PHYSFS_platformOpenWrite(const char *filename); + + +/* + * Open a file for appending. (filename) is in platform-dependent notation. If + * the file exists, the file pointer should be place just past the end of the + * file, so that the first write will be one byte after the current end of + * the file. If the file doesn't exist, it should be created as a zero-byte + * file. The file pointer should be positioned on the first byte of the file. + * + * The return value will be some platform-specific datatype that is opaque to + * the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32, + * etc. + * + * Opening a file for append multiple times has undefined results. + * + * Call __PHYSFS_setError() and return (NULL) if the file can't be opened. + */ +void *__PHYSFS_platformOpenAppend(const char *filename); + +/* + * Read more data from a platform-specific file handle. (opaque) should be + * cast to whatever data type your platform uses. Read a maximum of (len) + * 8-bit bytes to the area pointed to by (buf). If there isn't enough data + * available, return the number of bytes read, and position the file pointer + * immediately after those bytes. + * On success, return (len) and position the file pointer immediately past + * the end of the last read byte. Return (-1) if there is a catastrophic + * error, and call __PHYSFS_setError() to describe the problem; the file + * pointer should not move in such a case. A partial read is success; only + * return (-1) on total failure; presumably, the next read call after a + * partial read will fail as such. + */ +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len); + +/* + * Write more data to a platform-specific file handle. (opaque) should be + * cast to whatever data type your platform uses. Write a maximum of (len) + * 8-bit bytes from the area pointed to by (buffer). If there is a problem, + * return the number of bytes written, and position the file pointer + * immediately after those bytes. Return (-1) if there is a catastrophic + * error, and call __PHYSFS_setError() to describe the problem; the file + * pointer should not move in such a case. A partial write is success; only + * return (-1) on total failure; presumably, the next write call after a + * partial write will fail as such. + */ +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len); + +/* + * Set the file pointer to a new position. (opaque) should be cast to + * whatever data type your platform uses. (pos) specifies the number + * of 8-bit bytes to seek to from the start of the file. Seeking past the + * end of the file is an error condition, and you should check for it. + * + * Not all file types can seek; this is to be expected by the caller. + * + * On error, call __PHYSFS_setError() and return zero. On success, return + * a non-zero value. + */ +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos); + + +/* + * Get the file pointer's position, in an 8-bit byte offset from the start of + * the file. (opaque) should be cast to whatever data type your platform + * uses. + * + * Not all file types can "tell"; this is to be expected by the caller. + * + * On error, call __PHYSFS_setError() and return -1. On success, return >= 0. + */ +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque); + + +/* + * Determine the current size of a file, in 8-bit bytes, from an open file. + * + * The caller expects that this information may not be available for all + * file types on all platforms. + * + * Return -1 if you can't do it, and call __PHYSFS_setError(). Otherwise, + * return the file length in 8-bit bytes. + */ +PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle); + + +/* + * !!! FIXME: comment me. + */ +int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat); + +/* + * Flush any pending writes to disk. (opaque) should be cast to whatever data + * type your platform uses. Be sure to check for errors; the caller expects + * that this function can fail if there was a flushing error, etc. + * + * Return zero on failure, non-zero on success. + */ +int __PHYSFS_platformFlush(void *opaque); + +/* + * Close file and deallocate resources. (opaque) should be cast to whatever + * data type your platform uses. This should close the file in any scenario: + * flushing is a separate function call, and this function should never fail. + * + * You should clean up all resources associated with (opaque); the pointer + * will be considered invalid after this call. + */ +void __PHYSFS_platformClose(void *opaque); + +/* + * Platform implementation of PHYSFS_getCdRomDirsCallback()... + * CD directories are discovered and reported to the callback one at a time. + * Pointers passed to the callback are assumed to be invalid to the + * application after the callback returns, so you can free them or whatever. + * Callback does not assume results will be sorted in any meaningful way. + */ +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data); + +/* + * Calculate the base dir, if your platform needs special consideration. + * Just return NULL if the standard routines will suffice. (see + * calculateBaseDir() in physfs.c ...) + * Your string must end with a dir separator if you don't return NULL. + * Caller will allocator.Free() the retval if it's not NULL. + */ +char *__PHYSFS_platformCalcBaseDir(const char *argv0); + +/* + * Get the platform-specific user dir. + * As of PhysicsFS 2.1, returning NULL means fatal error. + * Your string must end with a dir separator if you don't return NULL. + * Caller will allocator.Free() the retval if it's not NULL. + */ +char *__PHYSFS_platformCalcUserDir(void); + + +/* This is the cached version from PHYSFS_init(). This is a fast call. */ +const char *__PHYSFS_getUserDir(void); /* not deprecated internal version. */ + + +/* + * Get the platform-specific pref dir. + * Returning NULL means fatal error. + * Your string must end with a dir separator if you don't return NULL. + * Caller will allocator.Free() the retval if it's not NULL. + * Caller will make missing directories if necessary; this just reports + * the final path. + */ +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app); + + +/* + * Return a pointer that uniquely identifies the current thread. + * On a platform without threading, (0x1) will suffice. These numbers are + * arbitrary; the only requirement is that no two threads have the same + * pointer. + */ +void *__PHYSFS_platformGetThreadID(void); + + +/* + * Enumerate a directory of files. This follows the rules for the + * PHYSFS_Archiver->enumerateFiles() method (see above), except that the + * (dirName) that is passed to this function is converted to + * platform-DEPENDENT notation by the caller. The PHYSFS_Archiver version + * uses platform-independent notation. Note that ".", "..", and other + * metaentries should always be ignored. + */ +void __PHYSFS_platformEnumerateFiles(const char *dirname, + int omitSymLinks, + PHYSFS_EnumFilesCallback callback, + const char *origdir, + void *callbackdata); + +/* + * Make a directory in the actual filesystem. (path) is specified in + * platform-dependent notation. On error, return zero and set the error + * message. Return non-zero on success. + */ +int __PHYSFS_platformMkDir(const char *path); + + +/* + * Remove a file or directory entry in the actual filesystem. (path) is + * specified in platform-dependent notation. Note that this deletes files + * _and_ directories, so you might need to do some determination. + * Non-empty directories should report an error and not delete themselves + * or their contents. + * + * Deleting a symlink should remove the link, not what it points to. + * + * On error, return zero and set the error message. Return non-zero on success. + */ +int __PHYSFS_platformDelete(const char *path); + + +/* + * Create a platform-specific mutex. This can be whatever datatype your + * platform uses for mutexes, but it is cast to a (void *) for abstractness. + * + * Return (NULL) if you couldn't create one. Systems without threads can + * return any arbitrary non-NULL value. + */ +void *__PHYSFS_platformCreateMutex(void); + +/* + * Destroy a platform-specific mutex, and clean up any resources associated + * with it. (mutex) is a value previously returned by + * __PHYSFS_platformCreateMutex(). This can be a no-op on single-threaded + * platforms. + */ +void __PHYSFS_platformDestroyMutex(void *mutex); + +/* + * Grab possession of a platform-specific mutex. Mutexes should be recursive; + * that is, the same thread should be able to call this function multiple + * times in a row without causing a deadlock. This function should block + * until a thread can gain possession of the mutex. + * + * Return non-zero if the mutex was grabbed, zero if there was an + * unrecoverable problem grabbing it (this should not be a matter of + * timing out! We're talking major system errors; block until the mutex + * is available otherwise.) + * + * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this + * function, you'll cause an infinite recursion. This means you can't + * use the BAIL_*MACRO* macros, either. + */ +int __PHYSFS_platformGrabMutex(void *mutex); + +/* + * Relinquish possession of the mutex when this method has been called + * once for each time that platformGrabMutex was called. Once possession has + * been released, the next thread in line to grab the mutex (if any) may + * proceed. + * + * _DO NOT_ call __PHYSFS_setError() in here! Since setError calls this + * function, you'll cause an infinite recursion. This means you can't + * use the BAIL_*MACRO* macros, either. + */ +void __PHYSFS_platformReleaseMutex(void *mutex); + +/* + * Called at the start of PHYSFS_init() to prepare the allocator, if the user + * hasn't selected their own allocator via PHYSFS_setAllocator(). + * If the platform has a custom allocator, it should fill in the fields of + * (a) with the proper function pointers and return non-zero. + * If the platform just wants to use malloc()/free()/etc, return zero + * immediately and the higher level will handle it. The Init and Deinit + * fields of (a) are optional...set them to NULL if you don't need them. + * Everything else must be implemented. All rules follow those for + * PHYSFS_setAllocator(). If Init isn't NULL, it will be called shortly + * after this function returns non-zero. + */ +int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a); + +#ifdef __cplusplus +} +#endif + +#endif + +/* end of physfs_internal.h ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_miniz.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_miniz.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,698 @@ +/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c) + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated May 20, 2011 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers. +*/ +#ifndef TINFL_HEADER_INCLUDED +#define TINFL_HEADER_INCLUDED + +typedef PHYSFS_uint8 mz_uint8; +typedef PHYSFS_sint16 mz_int16; +typedef PHYSFS_uint16 mz_uint16; +typedef PHYSFS_uint32 mz_uint32; +typedef unsigned int mz_uint; +typedef PHYSFS_uint64 mz_uint64; + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. */ +typedef unsigned long mz_ulong; + +/* Heap allocation callbacks. */ +typedef void *(*mz_alloc_func)(void *opaque, unsigned int items, unsigned int size); +typedef void (*mz_free_func)(void *opaque, void *address); + +#if defined(_M_IX86) || defined(_M_X64) +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +/* Decompression flags. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#endif /* #ifdef TINFL_HEADER_INCLUDED */ + +/* ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) */ + +#ifndef TINFL_HEADER_FILE_ONLY + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +/* TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never */ +/* reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. */ +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +static tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other stuff is for advanced use. */ +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +/* Compression levels. */ +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_DEFAULT_COMPRESSION = -1 }; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +static int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + /* if (!pStream->zalloc) pStream->zalloc = def_alloc_func; */ + /* if (!pStream->zfree) pStream->zfree = def_free_func; */ + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +static int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +static int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +/* make this a drop-in replacement for zlib... */ + #define voidpf void* + #define uInt unsigned int + #define z_stream mz_stream + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define Z_SYNC_FLUSH MZ_SYNC_FLUSH + #define Z_FINISH MZ_FINISH + #define Z_OK MZ_OK + #define Z_STREAM_END MZ_STREAM_END + #define Z_NEED_DICT MZ_NEED_DICT + #define Z_ERRNO MZ_ERRNO + #define Z_STREAM_ERROR MZ_STREAM_ERROR + #define Z_DATA_ERROR MZ_DATA_ERROR + #define Z_MEM_ERROR MZ_MEM_ERROR + #define Z_BUF_ERROR MZ_BUF_ERROR + #define Z_VERSION_ERROR MZ_VERSION_ERROR + #define MAX_WBITS 15 + +#endif /* #ifndef TINFL_HEADER_FILE_ONLY */ + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_platforms.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_platforms.h Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,58 @@ +#ifndef _INCL_PHYSFS_PLATFORMS +#define _INCL_PHYSFS_PLATFORMS + +#ifndef __PHYSICSFS_INTERNAL__ +#error Do not include this header from your applications. +#endif + +/* + * These only define the platforms to determine which files in the platforms + * directory should be compiled. For example, technically BeOS can be called + * a "unix" system, but since it doesn't use unix.c, we don't define + * PHYSFS_PLATFORM_UNIX on that system. + */ + +#if (defined __HAIKU__) +# define PHYSFS_PLATFORM_HAIKU 1 +# define PHYSFS_PLATFORM_BEOS 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif ((defined __BEOS__) || (defined __beos__)) +# define PHYSFS_PLATFORM_BEOS 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif (defined _WIN32_WCE) || (defined _WIN64_WCE) +# error PocketPC support was dropped from PhysicsFS 2.1. Sorry. +#elif (((defined _WIN32) || (defined _WIN64)) && (!defined __CYGWIN__)) +# define PHYSFS_PLATFORM_WINDOWS 1 +#elif (defined OS2) +# error OS/2 support was dropped from PhysicsFS 2.1. Sorry. +#elif ((defined __MACH__) && (defined __APPLE__)) +/* To check if iphone or not, we need to include this file */ +# include +# if ((TARGET_IPHONE_SIMULATOR) || (TARGET_OS_IPHONE)) +# define PHYSFS_NO_CDROM_SUPPORT 1 +# endif +# define PHYSFS_PLATFORM_MACOSX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif defined(macintosh) +# error Classic Mac OS support was dropped from PhysicsFS 2.0. Move to OS X. +#elif defined(__linux) +# define PHYSFS_PLATFORM_LINUX 1 +# define PHYSFS_PLATFORM_UNIX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif defined(__sun) || defined(sun) +# define PHYSFS_PLATFORM_SOLARIS 1 +# define PHYSFS_PLATFORM_UNIX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) +# define PHYSFS_PLATFORM_BSD 1 +# define PHYSFS_PLATFORM_UNIX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif defined(unix) || defined(__unix__) +# define PHYSFS_PLATFORM_UNIX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#else +# error Unknown platform. +#endif + +#endif /* include-once blocker. */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/physfs_unicode.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/physfs_unicode.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,528 @@ +#define __PHYSICSFS_INTERNAL__ +#include "physfs_internal.h" + + +/* + * From rfc3629, the UTF-8 spec: + * http://www.ietf.org/rfc/rfc3629.txt + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+--------------------------------------------- + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + + +/* + * This may not be the best value, but it's one that isn't represented + * in Unicode (0x10FFFF is the largest codepoint value). We return this + * value from utf8codepoint() if there's bogus bits in the + * stream. utf8codepoint() will turn this value into something + * reasonable (like a question mark), for text that wants to try to recover, + * whereas utf8valid() will use the value to determine if a string has bad + * bits. + */ +#define UNICODE_BOGUS_CHAR_VALUE 0xFFFFFFFF + +/* + * This is the codepoint we currently return when there was bogus bits in a + * UTF-8 string. May not fly in Asian locales? + */ +#define UNICODE_BOGUS_CHAR_CODEPOINT '?' + +static PHYSFS_uint32 utf8codepoint(const char **_str) +{ + const char *str = *_str; + PHYSFS_uint32 retval = 0; + PHYSFS_uint32 octet = (PHYSFS_uint32) ((PHYSFS_uint8) *str); + PHYSFS_uint32 octet2, octet3, octet4; + + if (octet == 0) /* null terminator, end of string. */ + return 0; + + else if (octet < 128) /* one octet char: 0 to 127 */ + { + (*_str)++; /* skip to next possible start of codepoint. */ + return octet; + } /* else if */ + + else if ((octet > 127) && (octet < 192)) /* bad (starts with 10xxxxxx). */ + { + /* + * Apparently each of these is supposed to be flagged as a bogus + * char, instead of just resyncing to the next valid codepoint. + */ + (*_str)++; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + else if (octet < 224) /* two octets */ + { + (*_str)++; /* advance at least one byte in case of an error */ + octet -= (128+64); + octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 1; /* skip to next possible start of codepoint. */ + retval = ((octet << 6) | (octet2 - 128)); + if ((retval >= 0x80) && (retval <= 0x7FF)) + return retval; + } /* else if */ + + else if (octet < 240) /* three octets */ + { + (*_str)++; /* advance at least one byte in case of an error */ + octet -= (128+64+32); + octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 2; /* skip to next possible start of codepoint. */ + retval = ( ((octet << 12)) | ((octet2-128) << 6) | ((octet3-128)) ); + + /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */ + switch (retval) + { + case 0xD800: + case 0xDB7F: + case 0xDB80: + case 0xDBFF: + case 0xDC00: + case 0xDF80: + case 0xDFFF: + return UNICODE_BOGUS_CHAR_VALUE; + } /* switch */ + + /* 0xFFFE and 0xFFFF are illegal, too, so we check them at the edge. */ + if ((retval >= 0x800) && (retval <= 0xFFFD)) + return retval; + } /* else if */ + + else if (octet < 248) /* four octets */ + { + (*_str)++; /* advance at least one byte in case of an error */ + octet -= (128+64+32+16); + octet2 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet2 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet3 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet3 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet4 = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet4 & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 3; /* skip to next possible start of codepoint. */ + retval = ( ((octet << 18)) | ((octet2 - 128) << 12) | + ((octet3 - 128) << 6) | ((octet4 - 128)) ); + if ((retval >= 0x10000) && (retval <= 0x10FFFF)) + return retval; + } /* else if */ + + /* + * Five and six octet sequences became illegal in rfc3629. + * We throw the codepoint away, but parse them to make sure we move + * ahead the right number of bytes and don't overflow the buffer. + */ + + else if (octet < 252) /* five octets */ + { + (*_str)++; /* advance at least one byte in case of an error */ + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 4; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + else /* six octets */ + { + (*_str)++; /* advance at least one byte in case of an error */ + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + octet = (PHYSFS_uint32) ((PHYSFS_uint8) *(++str)); + if ((octet & (128+64)) != 128) /* Format isn't 10xxxxxx? */ + return UNICODE_BOGUS_CHAR_VALUE; + + *_str += 6; /* skip to next possible start of codepoint. */ + return UNICODE_BOGUS_CHAR_VALUE; + } /* else if */ + + return UNICODE_BOGUS_CHAR_VALUE; +} /* utf8codepoint */ + + +void PHYSFS_utf8ToUcs4(const char *src, PHYSFS_uint32 *dst, PHYSFS_uint64 len) +{ + len -= sizeof (PHYSFS_uint32); /* save room for null char. */ + while (len >= sizeof (PHYSFS_uint32)) + { + PHYSFS_uint32 cp = utf8codepoint(&src); + if (cp == 0) + break; + else if (cp == UNICODE_BOGUS_CHAR_VALUE) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + *(dst++) = cp; + len -= sizeof (PHYSFS_uint32); + } /* while */ + + *dst = 0; +} /* PHYSFS_utf8ToUcs4 */ + + +void PHYSFS_utf8ToUcs2(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len) +{ + len -= sizeof (PHYSFS_uint16); /* save room for null char. */ + while (len >= sizeof (PHYSFS_uint16)) + { + PHYSFS_uint32 cp = utf8codepoint(&src); + if (cp == 0) + break; + else if (cp == UNICODE_BOGUS_CHAR_VALUE) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + + if (cp > 0xFFFF) /* UTF-16 surrogates (bogus chars in UCS-2) */ + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + + *(dst++) = cp; + len -= sizeof (PHYSFS_uint16); + } /* while */ + + *dst = 0; +} /* PHYSFS_utf8ToUcs2 */ + + +void PHYSFS_utf8ToUtf16(const char *src, PHYSFS_uint16 *dst, PHYSFS_uint64 len) +{ + len -= sizeof (PHYSFS_uint16); /* save room for null char. */ + while (len >= sizeof (PHYSFS_uint16)) + { + PHYSFS_uint32 cp = utf8codepoint(&src); + if (cp == 0) + break; + else if (cp == UNICODE_BOGUS_CHAR_VALUE) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + + if (cp > 0xFFFF) /* encode as surrogate pair */ + { + if (len < (sizeof (PHYSFS_uint16) * 2)) + break; /* not enough room for the pair, stop now. */ + + cp -= 0x10000; /* Make this a 20-bit value */ + + *(dst++) = 0xD800 + ((cp >> 10) & 0x3FF); + len -= sizeof (PHYSFS_uint16); + + cp = 0xDC00 + (cp & 0x3FF); + } /* if */ + + *(dst++) = cp; + len -= sizeof (PHYSFS_uint16); + } /* while */ + + *dst = 0; +} /* PHYSFS_utf8ToUtf16 */ + +static void utf8fromcodepoint(PHYSFS_uint32 cp, char **_dst, PHYSFS_uint64 *_len) +{ + char *dst = *_dst; + PHYSFS_uint64 len = *_len; + + if (len == 0) + return; + + if (cp > 0x10FFFF) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else if ((cp == 0xFFFE) || (cp == 0xFFFF)) /* illegal values. */ + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else + { + /* There are seven "UTF-16 surrogates" that are illegal in UTF-8. */ + switch (cp) + { + case 0xD800: + case 0xDB7F: + case 0xDB80: + case 0xDBFF: + case 0xDC00: + case 0xDF80: + case 0xDFFF: + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + } /* switch */ + } /* else */ + + /* Do the encoding... */ + if (cp < 0x80) + { + *(dst++) = (char) cp; + len--; + } /* if */ + + else if (cp < 0x800) + { + if (len < 2) + len = 0; + else + { + *(dst++) = (char) ((cp >> 6) | 128 | 64); + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 2; + } /* else */ + } /* else if */ + + else if (cp < 0x10000) + { + if (len < 3) + len = 0; + else + { + *(dst++) = (char) ((cp >> 12) | 128 | 64 | 32); + *(dst++) = (char) ((cp >> 6) & 0x3F) | 128; + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 3; + } /* else */ + } /* else if */ + + else + { + if (len < 4) + len = 0; + else + { + *(dst++) = (char) ((cp >> 18) | 128 | 64 | 32 | 16); + *(dst++) = (char) ((cp >> 12) & 0x3F) | 128; + *(dst++) = (char) ((cp >> 6) & 0x3F) | 128; + *(dst++) = (char) (cp & 0x3F) | 128; + len -= 4; + } /* else if */ + } /* else */ + + *_dst = dst; + *_len = len; +} /* utf8fromcodepoint */ + +#define UTF8FROMTYPE(typ, src, dst, len) \ + if (len == 0) return; \ + len--; \ + while (len) \ + { \ + const PHYSFS_uint32 cp = (PHYSFS_uint32) ((typ) (*(src++))); \ + if (cp == 0) break; \ + utf8fromcodepoint(cp, &dst, &len); \ + } \ + *dst = '\0'; \ + +void PHYSFS_utf8FromUcs4(const PHYSFS_uint32 *src, char *dst, PHYSFS_uint64 len) +{ + UTF8FROMTYPE(PHYSFS_uint32, src, dst, len); +} /* PHYSFS_utf8FromUcs4 */ + +void PHYSFS_utf8FromUcs2(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len) +{ + UTF8FROMTYPE(PHYSFS_uint64, src, dst, len); +} /* PHYSFS_utf8FromUcs2 */ + +/* latin1 maps to unicode codepoints directly, we just utf-8 encode it. */ +void PHYSFS_utf8FromLatin1(const char *src, char *dst, PHYSFS_uint64 len) +{ + UTF8FROMTYPE(PHYSFS_uint8, src, dst, len); +} /* PHYSFS_utf8FromLatin1 */ + +#undef UTF8FROMTYPE + + +void PHYSFS_utf8FromUtf16(const PHYSFS_uint16 *src, char *dst, PHYSFS_uint64 len) +{ + if (len == 0) + return; + + len--; + while (len) + { + PHYSFS_uint32 cp = (PHYSFS_uint32) *(src++); + if (cp == 0) + break; + + /* Orphaned second half of surrogate pair? */ + if ((cp >= 0xDC00) && (cp <= 0xDFFF)) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else if ((cp >= 0xD800) && (cp <= 0xDBFF)) /* start surrogate pair! */ + { + const PHYSFS_uint32 pair = (PHYSFS_uint32) *src; + if ((pair < 0xDC00) || (pair > 0xDFFF)) + cp = UNICODE_BOGUS_CHAR_CODEPOINT; + else + { + src++; /* eat the other surrogate. */ + cp = (((cp - 0xD800) << 10) | (pair - 0xDC00)); + } /* else */ + } /* else if */ + + utf8fromcodepoint(cp, &dst, &len); + } /* while */ + + *dst = '\0'; +} /* PHYSFS_utf8FromUtf16 */ + + +typedef struct CaseFoldMapping +{ + PHYSFS_uint32 from; + PHYSFS_uint32 to0; + PHYSFS_uint32 to1; + PHYSFS_uint32 to2; +} CaseFoldMapping; + +typedef struct CaseFoldHashBucket +{ + const PHYSFS_uint8 count; + const CaseFoldMapping *list; +} CaseFoldHashBucket; + +#include "physfs_casefolding.h" + +static void locate_case_fold_mapping(const PHYSFS_uint32 from, + PHYSFS_uint32 *to) +{ + PHYSFS_uint32 i; + const PHYSFS_uint8 hashed = ((from ^ (from >> 8)) & 0xFF); + const CaseFoldHashBucket *bucket = &case_fold_hash[hashed]; + const CaseFoldMapping *mapping = bucket->list; + + for (i = 0; i < bucket->count; i++, mapping++) + { + if (mapping->from == from) + { + to[0] = mapping->to0; + to[1] = mapping->to1; + to[2] = mapping->to2; + return; + } /* if */ + } /* for */ + + /* Not found...there's no remapping for this codepoint. */ + to[0] = from; + to[1] = 0; + to[2] = 0; +} /* locate_case_fold_mapping */ + + +static int utf8codepointcmp(const PHYSFS_uint32 cp1, const PHYSFS_uint32 cp2) +{ + PHYSFS_uint32 folded1[3], folded2[3]; + locate_case_fold_mapping(cp1, folded1); + locate_case_fold_mapping(cp2, folded2); + return ( (folded1[0] == folded2[0]) && + (folded1[1] == folded2[1]) && + (folded1[2] == folded2[2]) ); +} /* utf8codepointcmp */ + + +int __PHYSFS_utf8stricmp(const char *str1, const char *str2) +{ + while (1) + { + const PHYSFS_uint32 cp1 = utf8codepoint(&str1); + const PHYSFS_uint32 cp2 = utf8codepoint(&str2); + if (!utf8codepointcmp(cp1, cp2)) break; + if (cp1 == 0) return 1; + } /* while */ + + return 0; +} /* __PHYSFS_utf8stricmp */ + + +int __PHYSFS_utf8strnicmp(const char *str1, const char *str2, PHYSFS_uint32 n) +{ + while (n > 0) + { + const PHYSFS_uint32 cp1 = utf8codepoint(&str1); + const PHYSFS_uint32 cp2 = utf8codepoint(&str2); + if (!utf8codepointcmp(cp1, cp2)) return 0; + if (cp1 == 0) return 1; + n--; + } /* while */ + + return 1; /* matched to n chars. */ +} /* __PHYSFS_utf8strnicmp */ + + +int __PHYSFS_stricmpASCII(const char *str1, const char *str2) +{ + while (1) + { + const char ch1 = *(str1++); + const char ch2 = *(str2++); + const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1; + const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2; + if (cp1 < cp2) + return -1; + else if (cp1 > cp2) + return 1; + else if (cp1 == 0) /* they're both null chars? */ + break; + } /* while */ + + return 0; +} /* __PHYSFS_stricmpASCII */ + + +int __PHYSFS_strnicmpASCII(const char *str1, const char *str2, PHYSFS_uint32 n) +{ + while (n-- > 0) + { + const char ch1 = *(str1++); + const char ch2 = *(str2++); + const char cp1 = ((ch1 >= 'A') && (ch1 <= 'Z')) ? (ch1+32) : ch1; + const char cp2 = ((ch2 >= 'A') && (ch2 <= 'Z')) ? (ch2+32) : ch2; + if (cp1 < cp2) + return -1; + else if (cp1 > cp2) + return 1; + else if (cp1 == 0) /* they're both null chars? */ + return 0; + } /* while */ + + return 0; +} /* __PHYSFS_strnicmpASCII */ + + +/* end of physfs_unicode.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/platform_beos.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/platform_beos.cpp Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,239 @@ +/* + * BeOS platform-dependent support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_BEOS + +#ifdef PHYSFS_PLATFORM_HAIKU +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include "physfs_internal.h" + +int __PHYSFS_platformInit(void) +{ + return 1; /* always succeed. */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + return 1; /* always succeed. */ +} /* __PHYSFS_platformDeinit */ + + +static char *getMountPoint(const char *devname, char *buf, size_t bufsize) +{ + BVolumeRoster mounts; + BVolume vol; + + mounts.Rewind(); + while (mounts.GetNextVolume(&vol) == B_NO_ERROR) + { + fs_info fsinfo; + fs_stat_dev(vol.Device(), &fsinfo); + if (strcmp(devname, fsinfo.device_name) == 0) + { + BDirectory directory; + BEntry entry; + BPath path; + const char *str; + + if ( (vol.GetRootDirectory(&directory) < B_OK) || + (directory.GetEntry(&entry) < B_OK) || + (entry.GetPath(&path) < B_OK) || + ( (str = path.Path()) == NULL) ) + return NULL; + + strncpy(buf, str, bufsize-1); + buf[bufsize-1] = '\0'; + return buf; + } /* if */ + } /* while */ + + return NULL; +} /* getMountPoint */ + + + /* + * This function is lifted from Simple Directmedia Layer (SDL): + * http://www.libsdl.org/ ... this is zlib-licensed code, too. + */ +static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data) +{ + BDirectory dir; + dir.SetTo(d); + if (dir.InitCheck() != B_NO_ERROR) + return; + + dir.Rewind(); + BEntry entry; + while (dir.GetNextEntry(&entry) >= 0) + { + BPath path; + const char *name; + entry_ref e; + + if (entry.GetPath(&path) != B_NO_ERROR) + continue; + + name = path.Path(); + + if (entry.GetRef(&e) != B_NO_ERROR) + continue; + + if (entry.IsDirectory()) + { + if (strcmp(e.name, "floppy") != 0) + tryDir(name, callback, data); + continue; + } /* if */ + + if (strcmp(e.name, "raw") != 0) /* ignore partitions. */ + continue; + + const int devfd = open(name, O_RDONLY); + if (devfd < 0) + continue; + + device_geometry g; + const int rc = ioctl(devfd, B_GET_GEOMETRY, &g, sizeof (g)); + close(devfd); + if (rc < 0) + continue; + + if (g.device_type != B_CD) + continue; + + char mntpnt[B_FILE_NAME_LENGTH]; + if (getMountPoint(name, mntpnt, sizeof (mntpnt))) + callback(data, mntpnt); + } /* while */ +} /* tryDir */ + + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ + tryDir("/dev/disk", cb, data); +} /* __PHYSFS_platformDetectAvailableCDs */ + + +static team_id getTeamID(void) +{ + thread_info info; + thread_id tid = find_thread(NULL); + get_thread_info(tid, &info); + return info.team; +} /* getTeamID */ + + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + image_info info; + int32 cookie = 0; + + while (get_next_image_info(0, &cookie, &info) == B_OK) + { + if (info.type == B_APP_IMAGE) + break; + } /* while */ + + BEntry entry(info.name, true); + BPath path; + status_t rc = entry.GetPath(&path); /* (path) now has binary's path. */ + assert(rc == B_OK); + rc = path.GetParent(&path); /* chop filename, keep directory. */ + assert(rc == B_OK); + const char *str = path.Path(); + assert(str != NULL); + const size_t len = strlen(str); + char *retval = (char *) allocator.Malloc(len + 2); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + strcpy(retval, str); + retval[len] = '/'; + retval[len+1] = '\0'; + return retval; +} /* __PHYSFS_platformCalcBaseDir */ + + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + const char *userdir = __PHYSFS_getUserDir(); + const char *append = "config/settings/"; + const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2; + char *retval = allocator.Malloc(len); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + snprintf(retval, len, "%s%s%s/", userdir, append, app); + return retval; +} /* __PHYSFS_platformCalcPrefDir */ + + +void *__PHYSFS_platformGetThreadID(void) +{ + return (void *) find_thread(NULL); +} /* __PHYSFS_platformGetThreadID */ + + +void *__PHYSFS_platformCreateMutex(void) +{ + return new BLocker("PhysicsFS lock", true); +} /* __PHYSFS_platformCreateMutex */ + + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + delete ((BLocker *) mutex); +} /* __PHYSFS_platformDestroyMutex */ + + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + return ((BLocker *) mutex)->Lock() ? 1 : 0; +} /* __PHYSFS_platformGrabMutex */ + + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + ((BLocker *) mutex)->Unlock(); +} /* __PHYSFS_platformReleaseMutex */ + + +int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a) +{ + return 0; /* just use malloc() and friends. */ +} /* __PHYSFS_platformSetDefaultAllocator */ + +#endif /* PHYSFS_PLATFORM_BEOS */ + +/* end of beos.cpp ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/platform_macosx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/platform_macosx.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,326 @@ +/* + * Mac OS X support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_MACOSX + +#include + +#if !defined(PHYSFS_NO_CDROM_SUPPORT) +#include /* !!! FIXME */ +#include +#include +#include +#include +#endif + +/* Seems to get defined in some system header... */ +#ifdef Free +#undef Free +#endif + +#include "physfs_internal.h" + + +/* Wrap PHYSFS_Allocator in a CFAllocator... */ +static CFAllocatorRef cfallocator = NULL; + +static CFStringRef cfallocDesc(const void *info) +{ + return CFStringCreateWithCString(cfallocator, "PhysicsFS", + kCFStringEncodingASCII); +} /* cfallocDesc */ + + +static void *cfallocMalloc(CFIndex allocSize, CFOptionFlags hint, void *info) +{ + return allocator.Malloc(allocSize); +} /* cfallocMalloc */ + + +static void cfallocFree(void *ptr, void *info) +{ + allocator.Free(ptr); +} /* cfallocFree */ + + +static void *cfallocRealloc(void *ptr, CFIndex newsize, + CFOptionFlags hint, void *info) +{ + if ((ptr == NULL) || (newsize <= 0)) + return NULL; /* ADC docs say you should always return NULL here. */ + return allocator.Realloc(ptr, newsize); +} /* cfallocRealloc */ + + +int __PHYSFS_platformInit(void) +{ + /* set up a CFAllocator, so Carbon can use the physfs allocator, too. */ + CFAllocatorContext ctx; + memset(&ctx, '\0', sizeof (ctx)); + ctx.copyDescription = cfallocDesc; + ctx.allocate = cfallocMalloc; + ctx.reallocate = cfallocRealloc; + ctx.deallocate = cfallocFree; + cfallocator = CFAllocatorCreate(kCFAllocatorUseContext, &ctx); + BAIL_IF_MACRO(!cfallocator, PHYSFS_ERR_OUT_OF_MEMORY, 0); + return 1; /* success. */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + CFRelease(cfallocator); + cfallocator = NULL; + return 1; /* always succeed. */ +} /* __PHYSFS_platformDeinit */ + + + +/* CD-ROM detection code... */ + +/* + * Code based on sample from Apple Developer Connection: + * http://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm + */ + +#if !defined(PHYSFS_NO_CDROM_SUPPORT) + +static int darwinIsWholeMedia(io_service_t service) +{ + int retval = 0; + CFTypeRef wholeMedia; + + if (!IOObjectConformsTo(service, kIOMediaClass)) + return 0; + + wholeMedia = IORegistryEntryCreateCFProperty(service, + CFSTR(kIOMediaWholeKey), + cfallocator, 0); + if (wholeMedia == NULL) + return 0; + + retval = CFBooleanGetValue(wholeMedia); + CFRelease(wholeMedia); + + return retval; +} /* darwinIsWholeMedia */ + + +static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort) +{ + int retval = 0; + CFMutableDictionaryRef matchingDict; + kern_return_t rc; + io_iterator_t iter; + io_service_t service; + + if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL) + return 0; + + rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter); + if ((rc != KERN_SUCCESS) || (!iter)) + return 0; + + service = IOIteratorNext(iter); + IOObjectRelease(iter); + if (!service) + return 0; + + rc = IORegistryEntryCreateIterator(service, kIOServicePlane, + kIORegistryIterateRecursively | kIORegistryIterateParents, &iter); + + if (!iter) + return 0; + + if (rc != KERN_SUCCESS) + { + IOObjectRelease(iter); + return 0; + } /* if */ + + IOObjectRetain(service); /* add an extra object reference... */ + + do + { + if (darwinIsWholeMedia(service)) + { + if ( (IOObjectConformsTo(service, kIOCDMediaClass)) || + (IOObjectConformsTo(service, kIODVDMediaClass)) ) + { + retval = 1; + } /* if */ + } /* if */ + IOObjectRelease(service); + } while ((service = IOIteratorNext(iter)) && (!retval)); + + IOObjectRelease(iter); + IOObjectRelease(service); + + return retval; +} /* darwinIsMountedDisc */ + +#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ + + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ +#if !defined(PHYSFS_NO_CDROM_SUPPORT) + const char *devPrefix = "/dev/"; + const int prefixLen = strlen(devPrefix); + mach_port_t masterPort = 0; + struct statfs *mntbufp; + int i, mounts; + + if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS) + BAIL_MACRO(PHYSFS_ERR_OS_ERROR, ) /*return void*/; + + mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */ + for (i = 0; i < mounts; i++) + { + char *dev = mntbufp[i].f_mntfromname; + char *mnt = mntbufp[i].f_mntonname; + if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */ + continue; + + dev += prefixLen; + if (darwinIsMountedDisc(dev, masterPort)) + cb(data, mnt); + } /* for */ +#endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */ +} /* __PHYSFS_platformDetectAvailableCDs */ + + +static char *convertCFString(CFStringRef cfstr) +{ + CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), + kCFStringEncodingUTF8) + 1; + char *retval = (char *) allocator.Malloc(len); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8)) + { + /* shrink overallocated buffer if possible... */ + CFIndex newlen = strlen(retval) + 1; + if (newlen < len) + { + void *ptr = allocator.Realloc(retval, newlen); + if (ptr != NULL) + retval = (char *) ptr; + } /* if */ + } /* if */ + + else /* probably shouldn't fail, but just in case... */ + { + allocator.Free(retval); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* else */ + + return retval; +} /* convertCFString */ + + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + CFURLRef cfurl = NULL; + CFStringRef cfstr = NULL; + CFMutableStringRef cfmutstr = NULL; + char *retval = NULL; + + cfurl = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + BAIL_IF_MACRO(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL); + cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle); + CFRelease(cfurl); + BAIL_IF_MACRO(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + cfmutstr = CFStringCreateMutableCopy(cfallocator, 0, cfstr); + CFRelease(cfstr); + BAIL_IF_MACRO(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + CFStringAppendCString(cfmutstr, "/", kCFStringEncodingUTF8); + retval = convertCFString(cfmutstr); + CFRelease(cfmutstr); + + return retval; /* whew. */ +} /* __PHYSFS_platformCalcBaseDir */ + + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + /* !!! FIXME: there's a real API to determine this */ + const char *userdir = __PHYSFS_getUserDir(); + const char *append = "Library/Application Support/"; + const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2; + char *retval = allocator.Malloc(len); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + snprintf(retval, len, "%s%s%s/", userdir, append, app); + return retval; +} /* __PHYSFS_platformCalcPrefDir */ + + +/* Platform allocator uses default CFAllocator at PHYSFS_init() time. */ + +static CFAllocatorRef cfallocdef = NULL; + +static int macosxAllocatorInit(void) +{ + int retval = 0; + cfallocdef = CFAllocatorGetDefault(); + retval = (cfallocdef != NULL); + if (retval) + CFRetain(cfallocdef); + return retval; +} /* macosxAllocatorInit */ + + +static void macosxAllocatorDeinit(void) +{ + if (cfallocdef != NULL) + { + CFRelease(cfallocdef); + cfallocdef = NULL; + } /* if */ +} /* macosxAllocatorDeinit */ + + +static void *macosxAllocatorMalloc(PHYSFS_uint64 s) +{ + if (!__PHYSFS_ui64FitsAddressSpace(s)) + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + return CFAllocatorAllocate(cfallocdef, (CFIndex) s, 0); +} /* macosxAllocatorMalloc */ + + +static void *macosxAllocatorRealloc(void *ptr, PHYSFS_uint64 s) +{ + if (!__PHYSFS_ui64FitsAddressSpace(s)) + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + return CFAllocatorReallocate(cfallocdef, ptr, (CFIndex) s, 0); +} /* macosxAllocatorRealloc */ + + +static void macosxAllocatorFree(void *ptr) +{ + CFAllocatorDeallocate(cfallocdef, ptr); +} /* macosxAllocatorFree */ + + +int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a) +{ + allocator.Init = macosxAllocatorInit; + allocator.Deinit = macosxAllocatorDeinit; + allocator.Malloc = macosxAllocatorMalloc; + allocator.Realloc = macosxAllocatorRealloc; + allocator.Free = macosxAllocatorFree; + return 1; /* return non-zero: we're supplying custom allocator. */ +} /* __PHYSFS_platformSetDefaultAllocator */ + +#endif /* PHYSFS_PLATFORM_MACOSX */ + +/* end of macosx.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/platform_posix.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/platform_posix.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,479 @@ +/* + * Posix-esque support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +/* !!! FIXME: check for EINTR? */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_POSIX + +#include +#include +#include +#include +#include +#include +#include +#include + +#if ((!defined PHYSFS_NO_THREAD_SUPPORT) && (!defined PHYSFS_PLATFORM_BEOS)) +#include +#endif + +#include "physfs_internal.h" + + +static PHYSFS_ErrorCode errcodeFromErrnoError(const int err) +{ + switch (err) + { + case 0: return PHYSFS_ERR_OK; + case EACCES: return PHYSFS_ERR_PERMISSION; + case EPERM: return PHYSFS_ERR_PERMISSION; + case EDQUOT: return PHYSFS_ERR_NO_SPACE; + case EIO: return PHYSFS_ERR_IO; + case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; + case EMLINK: return PHYSFS_ERR_NO_SPACE; + case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME; + case ENOENT: return PHYSFS_ERR_NO_SUCH_PATH; + case ENOSPC: return PHYSFS_ERR_NO_SPACE; + case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; + case EISDIR: return PHYSFS_ERR_NOT_A_FILE; + case EROFS: return PHYSFS_ERR_READ_ONLY; + case ETXTBSY: return PHYSFS_ERR_BUSY; + case EBUSY: return PHYSFS_ERR_BUSY; + case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY; + case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY; + default: return PHYSFS_ERR_OS_ERROR; + } /* switch */ +} /* errcodeFromErrnoError */ + + +static inline PHYSFS_ErrorCode errcodeFromErrno(void) +{ + return errcodeFromErrnoError(errno); +} /* errcodeFromErrno */ + + +static char *getUserDirByUID(void) +{ + uid_t uid = getuid(); + struct passwd *pw; + char *retval = NULL; + + pw = getpwuid(uid); + if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0')) + { + const size_t dlen = strlen(pw->pw_dir); + const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0; + retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep); + if (retval != NULL) + { + strcpy(retval, pw->pw_dir); + if (add_dirsep) + { + retval[dlen] = '/'; + retval[dlen+1] = '\0'; + } /* if */ + } /* if */ + } /* if */ + + return retval; +} /* getUserDirByUID */ + + +char *__PHYSFS_platformCalcUserDir(void) +{ + char *retval = NULL; + char *envr = getenv("HOME"); + + /* if the environment variable was set, make sure it's really a dir. */ + if (envr != NULL) + { + struct stat statbuf; + if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode))) + { + const size_t envrlen = strlen(envr); + const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0; + retval = allocator.Malloc(envrlen + 1 + add_dirsep); + if (retval) + { + strcpy(retval, envr); + if (add_dirsep) + { + retval[envrlen] = '/'; + retval[envrlen+1] = '\0'; + } /* if */ + } /* if */ + } /* if */ + } /* if */ + + if (retval == NULL) + retval = getUserDirByUID(); + + return retval; +} /* __PHYSFS_platformCalcUserDir */ + + +void __PHYSFS_platformEnumerateFiles(const char *dirname, + int omitSymLinks, + PHYSFS_EnumFilesCallback callback, + const char *origdir, + void *callbackdata) +{ + DIR *dir; + struct dirent *ent; + int bufsize = 0; + char *buf = NULL; + int dlen = 0; + + if (omitSymLinks) /* !!! FIXME: this malloc sucks. */ + { + dlen = strlen(dirname); + bufsize = dlen + 256; + buf = (char *) allocator.Malloc(bufsize); + if (buf == NULL) + return; + strcpy(buf, dirname); + if (buf[dlen - 1] != '/') + { + buf[dlen++] = '/'; + buf[dlen] = '\0'; + } /* if */ + } /* if */ + + errno = 0; + dir = opendir(dirname); + if (dir == NULL) + { + allocator.Free(buf); + return; + } /* if */ + + while ((ent = readdir(dir)) != NULL) + { + if (strcmp(ent->d_name, ".") == 0) + continue; + + if (strcmp(ent->d_name, "..") == 0) + continue; + + if (omitSymLinks) + { + PHYSFS_Stat statbuf; + int exists = 0; + char *p; + int len = strlen(ent->d_name) + dlen + 1; + if (len > bufsize) + { + p = (char *) allocator.Realloc(buf, len); + if (p == NULL) + continue; + buf = p; + bufsize = len; + } /* if */ + + strcpy(buf + dlen, ent->d_name); + + if (!__PHYSFS_platformStat(buf, &exists, &statbuf)) + continue; + else if (!exists) + continue; /* probably can't happen, but just in case. */ + else if (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK) + continue; + } /* if */ + + callback(callbackdata, origdir, ent->d_name); + } /* while */ + + allocator.Free(buf); + closedir(dir); +} /* __PHYSFS_platformEnumerateFiles */ + + +int __PHYSFS_platformMkDir(const char *path) +{ + const int rc = mkdir(path, S_IRWXU); + BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformMkDir */ + + +static void *doOpen(const char *filename, int mode) +{ + const int appending = (mode & O_APPEND); + int fd; + int *retval; + errno = 0; + + /* O_APPEND doesn't actually behave as we'd like. */ + mode &= ~O_APPEND; + + fd = open(filename, mode, S_IRUSR | S_IWUSR); + BAIL_IF_MACRO(fd < 0, errcodeFromErrno(), NULL); + + if (appending) + { + if (lseek(fd, 0, SEEK_END) < 0) + { + const int err = errno; + close(fd); + BAIL_MACRO(errcodeFromErrnoError(err), NULL); + } /* if */ + } /* if */ + + retval = (int *) allocator.Malloc(sizeof (int)); + if (!retval) + { + close(fd); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + *retval = fd; + return ((void *) retval); +} /* doOpen */ + + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, O_RDONLY); +} /* __PHYSFS_platformOpenRead */ + + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC); +} /* __PHYSFS_platformOpenWrite */ + + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND); +} /* __PHYSFS_platformOpenAppend */ + + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *) opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + rc = read(fd, buffer, (size_t) len); + BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), -1); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64) rc; +} /* __PHYSFS_platformRead */ + + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len) +{ + const int fd = *((int *) opaque); + ssize_t rc = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + rc = write(fd, (void *) buffer, (size_t) len); + BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), rc); + assert(rc >= 0); + assert(rc <= len); + return (PHYSFS_sint64) rc; +} /* __PHYSFS_platformWrite */ + + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + const int fd = *((int *) opaque); + const int rc = lseek(fd, (off_t) pos, SEEK_SET); + BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformSeek */ + + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + const int fd = *((int *) opaque); + PHYSFS_sint64 retval; + retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR); + BAIL_IF_MACRO(retval == -1, errcodeFromErrno(), -1); + return retval; +} /* __PHYSFS_platformTell */ + + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + const int fd = *((int *) opaque); + struct stat statbuf; + BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1); + return ((PHYSFS_sint64) statbuf.st_size); +} /* __PHYSFS_platformFileLength */ + + +int __PHYSFS_platformFlush(void *opaque) +{ + const int fd = *((int *) opaque); + BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformFlush */ + + +void __PHYSFS_platformClose(void *opaque) +{ + const int fd = *((int *) opaque); + (void) close(fd); /* we don't check this. You should have used flush! */ + allocator.Free(opaque); +} /* __PHYSFS_platformClose */ + + +int __PHYSFS_platformDelete(const char *path) +{ + BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0); + return 1; +} /* __PHYSFS_platformDelete */ + + +int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st) +{ + struct stat statbuf; + + if (lstat(filename, &statbuf) == -1) + { + *exists = (errno != ENOENT); + BAIL_MACRO(errcodeFromErrno(), 0); + } /* if */ + + *exists = 1; + + if (S_ISREG(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_REGULAR; + st->filesize = statbuf.st_size; + } /* if */ + + else if(S_ISDIR(statbuf.st_mode)) + { + st->filetype = PHYSFS_FILETYPE_DIRECTORY; + st->filesize = 0; + } /* else if */ + + else + { + st->filetype = PHYSFS_FILETYPE_OTHER; + st->filesize = statbuf.st_size; + } /* else */ + + st->modtime = statbuf.st_mtime; + st->createtime = statbuf.st_ctime; + st->accesstime = statbuf.st_atime; + + /* !!! FIXME: maybe we should just report full permissions? */ + st->readonly = access(filename, W_OK); + return 1; +} /* __PHYSFS_platformStat */ + + +#ifndef PHYSFS_PLATFORM_BEOS /* BeOS has its own code in platform_beos.cpp */ +#if (defined PHYSFS_NO_THREAD_SUPPORT) + +void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); } +void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); } +void __PHYSFS_platformDestroyMutex(void *mutex) {} +int __PHYSFS_platformGrabMutex(void *mutex) { return 1; } +void __PHYSFS_platformReleaseMutex(void *mutex) {} + +#else + +typedef struct +{ + pthread_mutex_t mutex; + pthread_t owner; + PHYSFS_uint32 count; +} PthreadMutex; + + +void *__PHYSFS_platformGetThreadID(void) +{ + return ( (void *) ((size_t) pthread_self()) ); +} /* __PHYSFS_platformGetThreadID */ + + +void *__PHYSFS_platformCreateMutex(void) +{ + int rc; + PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex)); + BAIL_IF_MACRO(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + rc = pthread_mutex_init(&m->mutex, NULL); + if (rc != 0) + { + allocator.Free(m); + BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL); + } /* if */ + + m->count = 0; + m->owner = (pthread_t) 0xDEADBEEF; + return ((void *) m); +} /* __PHYSFS_platformCreateMutex */ + + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *) mutex; + + /* Destroying a locked mutex is a bug, but we'll try to be helpful. */ + if ((m->owner == pthread_self()) && (m->count > 0)) + pthread_mutex_unlock(&m->mutex); + + pthread_mutex_destroy(&m->mutex); + allocator.Free(m); +} /* __PHYSFS_platformDestroyMutex */ + + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *) mutex; + pthread_t tid = pthread_self(); + if (m->owner != tid) + { + if (pthread_mutex_lock(&m->mutex) != 0) + return 0; + m->owner = tid; + } /* if */ + + m->count++; + return 1; +} /* __PHYSFS_platformGrabMutex */ + + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + PthreadMutex *m = (PthreadMutex *) mutex; + assert(m->owner == pthread_self()); /* catch programming errors. */ + assert(m->count > 0); /* catch programming errors. */ + if (m->owner == pthread_self()) + { + if (--m->count == 0) + { + m->owner = (pthread_t) 0xDEADBEEF; + pthread_mutex_unlock(&m->mutex); + } /* if */ + } /* if */ +} /* __PHYSFS_platformReleaseMutex */ + +#endif /* !PHYSFS_NO_THREAD_SUPPORT */ +#endif /* !PHYSFS_PLATFORM_BEOS */ + +#endif /* PHYSFS_PLATFORM_POSIX */ + +/* end of posix.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/platform_unix.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/platform_unix.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,344 @@ +/* + * Unix support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_UNIX + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H) +#define PHYSFS_HAVE_MNTENT_H 1 +#elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H) +#define PHYSFS_HAVE_SYS_MNTTAB_H 1 +#elif PHYSFS_PLATFORM_BSD && !defined(PHYSFS_HAVE_SYS_UCRED_H) +#define PHYSFS_HAVE_SYS_UCRED_H 1 +#endif + +#ifdef PHYSFS_HAVE_SYS_UCRED_H +# ifdef PHYSFS_HAVE_MNTENT_H +# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */ +# endif +# include +# include +#endif + +#ifdef PHYSFS_HAVE_MNTENT_H +#include +#endif + +#ifdef PHYSFS_HAVE_SYS_MNTTAB_H +#include +#endif + +#include "physfs_internal.h" + +int __PHYSFS_platformInit(void) +{ + return 1; /* always succeed. */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + return 1; /* always succeed. */ +} /* __PHYSFS_platformDeinit */ + + +/* Stub version for platforms without CD-ROM support. */ +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ +#if (defined PHYSFS_NO_CDROM_SUPPORT) + /* no-op. */ + +#elif (defined PHYSFS_HAVE_SYS_UCRED_H) + int i; + struct statfs *mntbufp = NULL; + int mounts = getmntinfo(&mntbufp, MNT_WAIT); + + for (i = 0; i < mounts; i++) + { + int add_it = 0; + + if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0) + add_it = 1; + else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0) + add_it = 1; + + /* add other mount types here */ + + if (add_it) + cb(data, mntbufp[i].f_mntonname); + } /* for */ + +#elif (defined PHYSFS_HAVE_MNTENT_H) + FILE *mounts = NULL; + struct mntent *ent = NULL; + + mounts = setmntent("/etc/mtab", "r"); + BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/); + + while ( (ent = getmntent(mounts)) != NULL ) + { + int add_it = 0; + if (strcmp(ent->mnt_type, "iso9660") == 0) + add_it = 1; + else if (strcmp(ent->mnt_type, "udf") == 0) + add_it = 1; + + /* !!! FIXME: these might pick up floppy drives, right? */ + else if (strcmp(ent->mnt_type, "auto") == 0) + add_it = 1; + else if (strcmp(ent->mnt_type, "supermount") == 0) + add_it = 1; + + /* !!! FIXME: udf? automount? */ + + /* add other mount types here */ + + if (add_it) + cb(data, ent->mnt_dir); + } /* while */ + + endmntent(mounts); + +#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H) + FILE *mounts = fopen(MNTTAB, "r"); + struct mnttab ent; + + BAIL_IF_MACRO(mounts == NULL, PHYSFS_ERR_IO, /*return void*/); + while (getmntent(mounts, &ent) == 0) + { + int add_it = 0; + if (strcmp(ent.mnt_fstype, "hsfs") == 0) + add_it = 1; + + /* add other mount types here */ + + if (add_it) + cb(data, ent.mnt_mountp); + } /* while */ + + fclose(mounts); + +#else +#error Unknown platform. Should have defined PHYSFS_NO_CDROM_SUPPORT, perhaps. +#endif +} /* __PHYSFS_platformDetectAvailableCDs */ + + +/* + * See where program (bin) resides in the $PATH specified by (envr). + * returns a copy of the first element in envr that contains it, or NULL + * if it doesn't exist or there were other problems. PHYSFS_SetError() is + * called if we have a problem. + * + * (envr) will be scribbled over, and you are expected to allocator.Free() the + * return value when you're done with it. + */ +static char *findBinaryInPath(const char *bin, char *envr) +{ + size_t alloc_size = 0; + char *exe = NULL; + char *start = envr; + char *ptr; + + assert(bin != NULL); + assert(envr != NULL); + + do + { + size_t size; + size_t binlen; + + ptr = strchr(start, ':'); /* find next $PATH separator. */ + if (ptr) + *ptr = '\0'; + + binlen = strlen(bin); + size = strlen(start) + binlen + 2; + if (size > alloc_size) + { + char *x = (char *) allocator.Realloc(exe, size); + if (!x) + { + if (exe != NULL) + allocator.Free(exe); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + alloc_size = size; + exe = x; + } /* if */ + + /* build full binary path... */ + strcpy(exe, start); + if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/')) + strcat(exe, "/"); + strcat(exe, bin); + + if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */ + { + exe[size - binlen] = '\0'; /* chop off filename, leave '/' */ + return exe; + } /* if */ + + start = ptr + 1; /* start points to beginning of next element. */ + } while (ptr != NULL); + + if (exe != NULL) + allocator.Free(exe); + + return NULL; /* doesn't exist in path. */ +} /* findBinaryInPath */ + + +static char *readSymLink(const char *path) +{ + ssize_t len = 64; + ssize_t rc = -1; + char *retval = NULL; + + while (1) + { + char *ptr = (char *) allocator.Realloc(retval, (size_t) len); + if (ptr == NULL) + break; /* out of memory. */ + retval = ptr; + + rc = readlink(path, retval, len); + if (rc == -1) + break; /* not a symlink, i/o error, etc. */ + + else if (rc < len) + { + retval[rc] = '\0'; /* readlink doesn't null-terminate. */ + return retval; /* we're good to go. */ + } /* else if */ + + len *= 2; /* grow buffer, try again. */ + } /* while */ + + if (retval != NULL) + allocator.Free(retval); + return NULL; +} /* readSymLink */ + + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + char *retval = NULL; + const char *envr = NULL; + + /* + * Try to avoid using argv0 unless forced to. If there's a Linux-like + * /proc filesystem, you can get the full path to the current process from + * the /proc/self/exe symlink. + */ + retval = readSymLink("/proc/self/exe"); + if (retval == NULL) + { + /* older kernels don't have /proc/self ... try PID version... */ + const unsigned long long pid = (unsigned long long) getpid(); + char path[64]; + const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid); + if ( (rc > 0) && (rc < sizeof(path)) ) + retval = readSymLink(path); + } /* if */ + + if (retval != NULL) /* chop off filename. */ + { + char *ptr = strrchr(retval, '/'); + if (ptr != NULL) + *(ptr+1) = '\0'; + else /* shouldn't happen, but just in case... */ + { + allocator.Free(retval); + retval = NULL; + } /* else */ + } /* if */ + + /* No /proc/self/exe, but we have an argv[0] we can parse? */ + if ((retval == NULL) && (argv0 != NULL)) + { + /* fast path: default behaviour can handle this. */ + if (strchr(argv0, '/') != NULL) + return NULL; /* higher level parses out real path from argv0. */ + + /* If there's no dirsep on argv0, then look through $PATH for it. */ + envr = getenv("PATH"); + if (envr != NULL) + { + char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1); + BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + strcpy(path, envr); + retval = findBinaryInPath(argv0, path); + __PHYSFS_smallFree(path); + } /* if */ + } /* if */ + + if (retval != NULL) + { + /* try to shrink buffer... */ + char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1); + if (ptr != NULL) + retval = ptr; /* oh well if it failed. */ + } /* if */ + + return retval; +} /* __PHYSFS_platformCalcBaseDir */ + + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + /* + * We use XDG's base directory spec, even if you're not on Linux. + * This isn't strictly correct, but the results are relatively sane + * in any case. + * + * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + */ + const char *envr = getenv("XDG_DATA_HOME"); + const char *append = "/"; + char *retval = NULL; + size_t len = 0; + + if (!envr) + { + /* You end up with "$HOME/.local/share/Game Name 2" */ + envr = __PHYSFS_getUserDir(); + BAIL_IF_MACRO(!envr, ERRPASS, NULL); /* oh well. */ + append = ".local/share/"; + } /* if */ + + len = strlen(envr) + strlen(append) + strlen(app) + 2; + retval = (char *) allocator.Malloc(len); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + snprintf(retval, len, "%s%s%s/", envr, append, app); + return retval; +} /* __PHYSFS_platformCalcPrefDir */ + + +int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a) +{ + return 0; /* just use malloc() and friends. */ +} /* __PHYSFS_platformSetDefaultAllocator */ + +#endif /* PHYSFS_PLATFORM_UNIX */ + +/* end of unix.c ... */ + diff -r 39f8ea1a441f -r bcebfc477459 misc/physfs/src/platform_windows.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/physfs/src/platform_windows.c Sat Nov 17 20:30:32 2012 -0500 @@ -0,0 +1,936 @@ +/* + * Windows support routines for PhysicsFS. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon, and made sane by Gregory S. Read. + */ + +#define __PHYSICSFS_INTERNAL__ +#include "physfs_platforms.h" + +#ifdef PHYSFS_PLATFORM_WINDOWS + +/* Forcibly disable UNICODE macro, since we manage this ourselves. */ +#ifdef UNICODE +#undef UNICODE +#endif + +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#include +#include +#include +#include + +#include "physfs_internal.h" + +#define LOWORDER_UINT64(pos) ((PHYSFS_uint32) (pos & 0xFFFFFFFF)) +#define HIGHORDER_UINT64(pos) ((PHYSFS_uint32) ((pos >> 32) & 0xFFFFFFFF)) + +/* + * Users without the platform SDK don't have this defined. The original docs + * for SetFilePointer() just said to compare with 0xFFFFFFFF, so this should + * work as desired. + */ +#define PHYSFS_INVALID_SET_FILE_POINTER 0xFFFFFFFF + +/* just in case... */ +#define PHYSFS_INVALID_FILE_ATTRIBUTES 0xFFFFFFFF + +/* Not defined before the Vista SDK. */ +#define PHYSFS_IO_REPARSE_TAG_SYMLINK 0xA000000C + + +#define UTF8_TO_UNICODE_STACK_MACRO(w_assignto, str) { \ + if (str == NULL) \ + w_assignto = NULL; \ + else { \ + const PHYSFS_uint64 len = (PHYSFS_uint64) ((strlen(str) + 1) * 2); \ + w_assignto = (WCHAR *) __PHYSFS_smallAlloc(len); \ + if (w_assignto != NULL) \ + PHYSFS_utf8ToUtf16(str, (PHYSFS_uint16 *) w_assignto, len); \ + } \ +} \ + +/* Note this counts WCHARs, not codepoints! */ +static PHYSFS_uint64 wStrLen(const WCHAR *wstr) +{ + PHYSFS_uint64 len = 0; + while (*(wstr++)) + len++; + return len; +} /* wStrLen */ + +static char *unicodeToUtf8Heap(const WCHAR *w_str) +{ + char *retval = NULL; + if (w_str != NULL) + { + void *ptr = NULL; + const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1; + retval = allocator.Malloc(len); + BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *) w_str, retval, len); + ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */ + if (ptr != NULL) + retval = (char *) ptr; + } /* if */ + return retval; +} /* unicodeToUtf8Heap */ + +/* !!! FIXME: do we really need readonly? If not, do we need this struct? */ +typedef struct +{ + HANDLE handle; + int readonly; +} WinApiFile; + +static HANDLE detectCDThreadHandle = NULL; +static HWND detectCDHwnd = 0; +static volatile int initialDiscDetectionComplete = 0; +static volatile DWORD drivesWithMediaBitmap = 0; + + +static PHYSFS_ErrorCode errcodeFromWinApiError(const DWORD err) +{ + /* + * win32 error codes are sort of a tricky thing; Microsoft intentionally + * doesn't list which ones a given API might trigger, there are several + * with overlapping and unclear meanings...and there's 16 thousand of + * them in Windows 7. It looks like the ones we care about are in the + * first 500, but I can't say this list is perfect; we might miss + * important values or misinterpret others. + * + * Don't treat this list as anything other than a work in progress. + */ + switch (err) + { + case ERROR_SUCCESS: return PHYSFS_ERR_OK; + case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION; + case ERROR_NETWORK_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION; + case ERROR_NOT_READY: return PHYSFS_ERR_IO; + case ERROR_CRC: return PHYSFS_ERR_IO; + case ERROR_SEEK: return PHYSFS_ERR_IO; + case ERROR_SECTOR_NOT_FOUND: return PHYSFS_ERR_IO; + case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_IO; + case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO; + case ERROR_READ_FAULT: return PHYSFS_ERR_IO; + case ERROR_DEV_NOT_EXIST: return PHYSFS_ERR_IO; + /* !!! FIXME: ?? case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP; */ + case ERROR_BUFFER_OVERFLOW: return PHYSFS_ERR_BAD_FILENAME; + case ERROR_INVALID_NAME: return PHYSFS_ERR_BAD_FILENAME; + case ERROR_BAD_PATHNAME: return PHYSFS_ERR_BAD_FILENAME; + case ERROR_DIRECTORY: return PHYSFS_ERR_BAD_FILENAME; + case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; + case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NO_SUCH_PATH; + case ERROR_DELETE_PENDING: return PHYSFS_ERR_NO_SUCH_PATH; + case ERROR_INVALID_DRIVE: return PHYSFS_ERR_NO_SUCH_PATH; + case ERROR_HANDLE_DISK_FULL: return PHYSFS_ERR_NO_SPACE; + case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE; + /* !!! FIXME: ?? case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH; */ + /* !!! FIXME: ?? case EISDIR: return PHYSFS_ERR_NOT_A_FILE; */ + case ERROR_WRITE_PROTECT: return PHYSFS_ERR_READ_ONLY; + case ERROR_LOCK_VIOLATION: return PHYSFS_ERR_BUSY; + case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_BUSY; + case ERROR_CURRENT_DIRECTORY: return PHYSFS_ERR_BUSY; + case ERROR_DRIVE_LOCKED: return PHYSFS_ERR_BUSY; + case ERROR_PATH_BUSY: return PHYSFS_ERR_BUSY; + case ERROR_BUSY: return PHYSFS_ERR_BUSY; + case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY; + case ERROR_OUTOFMEMORY: return PHYSFS_ERR_OUT_OF_MEMORY; + case ERROR_DIR_NOT_EMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY; + default: return PHYSFS_ERR_OS_ERROR; + } /* switch */ +} /* errcodeFromWinApiError */ + +static inline PHYSFS_ErrorCode errcodeFromWinApi(void) +{ + return errcodeFromWinApiError(GetLastError()); +} /* errcodeFromWinApi */ + + +typedef BOOL (WINAPI *fnSTEM)(DWORD, LPDWORD b); + +static DWORD pollDiscDrives(void) +{ + /* Try to use SetThreadErrorMode(), which showed up in Windows 7. */ + HANDLE lib = LoadLibraryA("kernel32.dll"); + fnSTEM stem = NULL; + char drive[4] = { 'x', ':', '\\', '\0' }; + DWORD oldErrorMode = 0; + DWORD drives = 0; + DWORD i; + + if (lib) + stem = (fnSTEM) GetProcAddress(lib, "SetThreadErrorMode"); + + if (stem) + stem(SEM_FAILCRITICALERRORS, &oldErrorMode); + else + oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + + /* Do detection. This may block if a disc is spinning up. */ + for (i = 'A'; i <= 'Z'; i++) + { + DWORD tmp = 0; + drive[0] = (char) i; + if (GetDriveTypeA(drive) != DRIVE_CDROM) + continue; + + /* If this function succeeds, there's media in the drive */ + if (GetVolumeInformationA(drive, NULL, 0, NULL, NULL, &tmp, NULL, 0)) + drives |= (1 << (i - 'A')); + } /* for */ + + if (stem) + stem(oldErrorMode, NULL); + else + SetErrorMode(oldErrorMode); + + if (lib) + FreeLibrary(lib); + + return drives; +} /* pollDiscDrives */ + + +static LRESULT CALLBACK detectCDWndProc(HWND hwnd, UINT msg, + WPARAM wp, LPARAM lparam) +{ + PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR) lparam; + PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME) lparam; + const int removed = (wp == DBT_DEVICEREMOVECOMPLETE); + + if (msg == WM_DESTROY) + return 0; + else if ((msg != WM_DEVICECHANGE) || + ((wp != DBT_DEVICEARRIVAL) && (wp != DBT_DEVICEREMOVECOMPLETE)) || + (lpdb->dbch_devicetype != DBT_DEVTYP_VOLUME) || + ((lpdbv->dbcv_flags & DBTF_MEDIA) == 0)) + { + return DefWindowProcW(hwnd, msg, wp, lparam); + } /* else if */ + + if (removed) + drivesWithMediaBitmap &= ~lpdbv->dbcv_unitmask; + else + drivesWithMediaBitmap |= lpdbv->dbcv_unitmask; + + return TRUE; +} /* detectCDWndProc */ + + +static DWORD WINAPI detectCDThread(LPVOID lpParameter) +{ + const char *classname = "PhysicsFSDetectCDCatcher"; + const char *winname = "PhysicsFSDetectCDMsgWindow"; + HINSTANCE hInstance = GetModuleHandleW(NULL); + ATOM class_atom = 0; + WNDCLASSEXA wce; + MSG msg; + + memset(&wce, '\0', sizeof (wce)); + wce.cbSize = sizeof (wce); + wce.lpfnWndProc = detectCDWndProc; + wce.lpszClassName = classname; + wce.hInstance = hInstance; + class_atom = RegisterClassExA(&wce); + if (class_atom == 0) + { + initialDiscDetectionComplete = 1; /* let main thread go on. */ + return 0; + } /* if */ + + detectCDHwnd = CreateWindowExA(0, classname, winname, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, HWND_DESKTOP, NULL, hInstance, NULL); + + if (detectCDHwnd == NULL) + { + initialDiscDetectionComplete = 1; /* let main thread go on. */ + UnregisterClassA(classname, hInstance); + return 0; + } /* if */ + + /* We'll get events when discs come and go from now on. */ + + /* Do initial detection, possibly blocking awhile... */ + drivesWithMediaBitmap = pollDiscDrives(); + initialDiscDetectionComplete = 1; /* let main thread go on. */ + + do + { + const BOOL rc = GetMessageW(&msg, detectCDHwnd, 0, 0); + if ((rc == 0) || (rc == -1)) + break; /* don't care if WM_QUIT or error break this loop. */ + TranslateMessage(&msg); + DispatchMessageW(&msg); + } while (1); + + /* we've been asked to quit. */ + DestroyWindow(detectCDHwnd); + + do + { + const BOOL rc = GetMessage(&msg, detectCDHwnd, 0, 0); + if ((rc == 0) || (rc == -1)) + break; + TranslateMessage(&msg); + DispatchMessageW(&msg); + } while (1); + + UnregisterClassA(classname, hInstance); + + return 0; +} /* detectCDThread */ + + +void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data) +{ + char drive_str[4] = { 'x', ':', '\\', '\0' }; + DWORD drives = 0; + DWORD i; + + /* + * If you poll a drive while a user is inserting a disc, the OS will + * block this thread until the drive has spun up. So we swallow the risk + * once for initial detection, and spin a thread that will get device + * events thereafter, for apps that use this interface to poll for + * disc insertion. + */ + if (!detectCDThreadHandle) + { + initialDiscDetectionComplete = 0; + detectCDThreadHandle = CreateThread(NULL,0,detectCDThread,NULL,0,NULL); + if (detectCDThreadHandle == NULL) + return; /* oh well. */ + + while (!initialDiscDetectionComplete) + Sleep(50); + } /* if */ + + drives = drivesWithMediaBitmap; /* whatever the thread has seen, we take. */ + for (i = 'A'; i <= 'Z'; i++) + { + if (drives & (1 << (i - 'A'))) + { + drive_str[0] = (char) i; + cb(data, drive_str); + } /* if */ + } /* for */ +} /* __PHYSFS_platformDetectAvailableCDs */ + + +char *__PHYSFS_platformCalcBaseDir(const char *argv0) +{ + DWORD buflen = 64; + LPWSTR modpath = NULL; + char *retval = NULL; + + while (1) + { + DWORD rc; + void *ptr; + + if ( (ptr = allocator.Realloc(modpath, buflen*sizeof(WCHAR))) == NULL ) + { + allocator.Free(modpath); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + modpath = (LPWSTR) ptr; + + rc = GetModuleFileNameW(NULL, modpath, buflen); + if (rc == 0) + { + allocator.Free(modpath); + BAIL_MACRO(errcodeFromWinApi(), NULL); + } /* if */ + + if (rc < buflen) + { + buflen = rc; + break; + } /* if */ + + buflen *= 2; + } /* while */ + + if (buflen > 0) /* just in case... */ + { + WCHAR *ptr = (modpath + buflen) - 1; + while (ptr != modpath) + { + if (*ptr == '\\') + break; + ptr--; + } /* while */ + + if ((ptr == modpath) && (*ptr != '\\')) + __PHYSFS_setError(PHYSFS_ERR_OTHER_ERROR); /* oh well. */ + else + { + *(ptr+1) = '\0'; /* chop off filename. */ + retval = unicodeToUtf8Heap(modpath); + } /* else */ + } /* else */ + allocator.Free(modpath); + + return retval; /* w00t. */ +} /* __PHYSFS_platformCalcBaseDir */ + + +char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) +{ + /* + * Vista and later has a new API for this, but SHGetFolderPath works there, + * and apparently just wraps the new API. This is the new way to do it: + * + * SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, + * NULL, &wszPath); + */ + + WCHAR path[MAX_PATH]; + char *utf8 = NULL; + size_t len = 0; + char *retval = NULL; + + if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, + NULL, 0, path))) + BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL); + + utf8 = unicodeToUtf8Heap(path); + BAIL_IF_MACRO(!utf8, ERRPASS, NULL); + len = strlen(utf8) + strlen(org) + strlen(app) + 4; + retval = allocator.Malloc(len); + if (!retval) + { + allocator.Free(utf8); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + sprintf(retval, "%s\\%s\\%s\\", utf8, org, app); + return retval; +} /* __PHYSFS_platformCalcPrefDir */ + + +char *__PHYSFS_platformCalcUserDir(void) +{ + typedef BOOL (WINAPI *fnGetUserProfDirW)(HANDLE, LPWSTR, LPDWORD); + fnGetUserProfDirW pGetDir = NULL; + HANDLE lib = NULL; + HANDLE accessToken = NULL; /* Security handle to process */ + char *retval = NULL; + + lib = LoadLibraryA("userenv.dll"); + BAIL_IF_MACRO(!lib, errcodeFromWinApi(), NULL); + pGetDir=(fnGetUserProfDirW) GetProcAddress(lib,"GetUserProfileDirectoryW"); + GOTO_IF_MACRO(!pGetDir, errcodeFromWinApi(), done); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &accessToken)) + GOTO_MACRO(errcodeFromWinApi(), done); + else + { + DWORD psize = 0; + WCHAR dummy = 0; + LPWSTR wstr = NULL; + BOOL rc = 0; + + /* + * Should fail. Will write the size of the profile path in + * psize. Also note that the second parameter can't be + * NULL or the function fails. + */ + rc = pGetDir(accessToken, &dummy, &psize); + assert(!rc); /* !!! FIXME: handle this gracefully. */ + (void) rc; + + /* Allocate memory for the profile directory */ + wstr = (LPWSTR) __PHYSFS_smallAlloc((psize + 1) * sizeof (WCHAR)); + if (wstr != NULL) + { + if (pGetDir(accessToken, wstr, &psize)) + { + /* Make sure it ends in a dirsep. We allocated +1 for this. */ + if (wstr[psize - 2] != '\\') + { + wstr[psize - 1] = '\\'; + wstr[psize - 0] = '\0'; + } /* if */ + retval = unicodeToUtf8Heap(wstr); + } /* if */ + __PHYSFS_smallFree(wstr); + } /* if */ + + CloseHandle(accessToken); + } /* if */ + +done: + FreeLibrary(lib); + return retval; /* We made it: hit the showers. */ +} /* __PHYSFS_platformCalcUserDir */ + + +void *__PHYSFS_platformGetThreadID(void) +{ + return ( (void *) ((size_t) GetCurrentThreadId()) ); +} /* __PHYSFS_platformGetThreadID */ + + +static int isSymlinkAttrs(const DWORD attr, const DWORD tag) +{ + return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && + (tag == PHYSFS_IO_REPARSE_TAG_SYMLINK) ); +} /* isSymlinkAttrs */ + + +void __PHYSFS_platformEnumerateFiles(const char *dirname, + int omitSymLinks, + PHYSFS_EnumFilesCallback callback, + const char *origdir, + void *callbackdata) +{ + HANDLE dir = INVALID_HANDLE_VALUE; + WIN32_FIND_DATAW entw; + size_t len = strlen(dirname); + char *searchPath = NULL; + WCHAR *wSearchPath = NULL; + + /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */ + searchPath = (char *) __PHYSFS_smallAlloc(len + 3); + if (searchPath == NULL) + return; + + /* Copy current dirname */ + strcpy(searchPath, dirname); + + /* if there's no '\\' at the end of the path, stick one in there. */ + if (searchPath[len - 1] != '\\') + { + searchPath[len++] = '\\'; + searchPath[len] = '\0'; + } /* if */ + + /* Append the "*" to the end of the string */ + strcat(searchPath, "*"); + + UTF8_TO_UNICODE_STACK_MACRO(wSearchPath, searchPath); + if (!wSearchPath) + return; /* oh well. */ + + dir = FindFirstFileW(wSearchPath, &entw); + + __PHYSFS_smallFree(wSearchPath); + __PHYSFS_smallFree(searchPath); + if (dir == INVALID_HANDLE_VALUE) + return; + + do + { + const DWORD attr = entw.dwFileAttributes; + const DWORD tag = entw.dwReserved0; + const WCHAR *fn = entw.cFileName; + char *utf8; + + if ((fn[0] == '.') && (fn[1] == '\0')) + continue; + if ((fn[0] == '.') && (fn[1] == '.') && (fn[2] == '\0')) + continue; + if ((omitSymLinks) && (isSymlinkAttrs(attr, tag))) + continue; + + utf8 = unicodeToUtf8Heap(fn); + if (utf8 != NULL) + { + callback(callbackdata, origdir, utf8); + allocator.Free(utf8); + } /* if */ + } while (FindNextFileW(dir, &entw) != 0); + + FindClose(dir); +} /* __PHYSFS_platformEnumerateFiles */ + + +int __PHYSFS_platformMkDir(const char *path) +{ + WCHAR *wpath; + DWORD rc; + UTF8_TO_UNICODE_STACK_MACRO(wpath, path); + rc = CreateDirectoryW(wpath, NULL); + __PHYSFS_smallFree(wpath); + BAIL_IF_MACRO(rc == 0, errcodeFromWinApi(), 0); + return 1; +} /* __PHYSFS_platformMkDir */ + + +int __PHYSFS_platformInit(void) +{ + return 1; /* It's all good */ +} /* __PHYSFS_platformInit */ + + +int __PHYSFS_platformDeinit(void) +{ + if (detectCDThreadHandle) + { + if (detectCDHwnd) + PostMessageW(detectCDHwnd, WM_QUIT, 0, 0); + CloseHandle(detectCDThreadHandle); + detectCDThreadHandle = NULL; + initialDiscDetectionComplete = 0; + drivesWithMediaBitmap = 0; + } /* if */ + + return 1; /* It's all good */ +} /* __PHYSFS_platformDeinit */ + + +static void *doOpen(const char *fname, DWORD mode, DWORD creation, int rdonly) +{ + HANDLE fileh; + WinApiFile *retval; + WCHAR *wfname; + + UTF8_TO_UNICODE_STACK_MACRO(wfname, fname); + BAIL_IF_MACRO(!wfname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + fileh = CreateFileW(wfname, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); + __PHYSFS_smallFree(wfname); + + BAIL_IF_MACRO(fileh == INVALID_HANDLE_VALUE,errcodeFromWinApi(), NULL); + + retval = (WinApiFile *) allocator.Malloc(sizeof (WinApiFile)); + if (!retval) + { + CloseHandle(fileh); + BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + retval->readonly = rdonly; + retval->handle = fileh; + return retval; +} /* doOpen */ + + +void *__PHYSFS_platformOpenRead(const char *filename) +{ + return doOpen(filename, GENERIC_READ, OPEN_EXISTING, 1); +} /* __PHYSFS_platformOpenRead */ + + +void *__PHYSFS_platformOpenWrite(const char *filename) +{ + return doOpen(filename, GENERIC_WRITE, CREATE_ALWAYS, 0); +} /* __PHYSFS_platformOpenWrite */ + + +void *__PHYSFS_platformOpenAppend(const char *filename) +{ + void *retval = doOpen(filename, GENERIC_WRITE, OPEN_ALWAYS, 0); + if (retval != NULL) + { + HANDLE h = ((WinApiFile *) retval)->handle; + DWORD rc = SetFilePointer(h, 0, NULL, FILE_END); + if (rc == PHYSFS_INVALID_SET_FILE_POINTER) + { + const PHYSFS_ErrorCode err = errcodeFromWinApi(); + CloseHandle(h); + allocator.Free(retval); + BAIL_MACRO(err, NULL); + } /* if */ + } /* if */ + + return retval; +} /* __PHYSFS_platformOpenAppend */ + + +PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + PHYSFS_sint64 totalRead = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + while (len > 0) + { + const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len; + DWORD numRead = 0; + if (!ReadFile(Handle, buf, thislen, &numRead, NULL)) + BAIL_MACRO(errcodeFromWinApi(), -1); + len -= (PHYSFS_uint64) numRead; + totalRead += (PHYSFS_sint64) numRead; + if (numRead != thislen) + break; + } /* while */ + + return totalRead; +} /* __PHYSFS_platformRead */ + + +PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, + PHYSFS_uint64 len) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + PHYSFS_sint64 totalWritten = 0; + + if (!__PHYSFS_ui64FitsAddressSpace(len)) + BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1); + + while (len > 0) + { + const DWORD thislen = (len > 0xFFFFFFFF) ? 0xFFFFFFFF : (DWORD) len; + DWORD numWritten = 0; + if (!WriteFile(Handle, buffer, thislen, &numWritten, NULL)) + BAIL_MACRO(errcodeFromWinApi(), -1); + len -= (PHYSFS_uint64) numWritten; + totalWritten += (PHYSFS_sint64) numWritten; + if (numWritten != thislen) + break; + } /* while */ + + return totalWritten; +} /* __PHYSFS_platformWrite */ + + +int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + LONG HighOrderPos; + PLONG pHighOrderPos; + DWORD rc; + + /* Get the high order 32-bits of the position */ + HighOrderPos = HIGHORDER_UINT64(pos); + + /* + * MSDN: "If you do not need the high-order 32 bits, this + * pointer must be set to NULL." + */ + pHighOrderPos = (HighOrderPos) ? &HighOrderPos : NULL; + + /* Move pointer "pos" count from start of file */ + rc = SetFilePointer(Handle, LOWORDER_UINT64(pos), + pHighOrderPos, FILE_BEGIN); + + if ( (rc == PHYSFS_INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR) ) + { + BAIL_MACRO(errcodeFromWinApi(), 0); + } /* if */ + + return 1; /* No error occured */ +} /* __PHYSFS_platformSeek */ + + +PHYSFS_sint64 __PHYSFS_platformTell(void *opaque) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + LONG HighPos = 0; + DWORD LowPos; + PHYSFS_sint64 retval; + + /* Get current position */ + LowPos = SetFilePointer(Handle, 0, &HighPos, FILE_CURRENT); + if ( (LowPos == PHYSFS_INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR) ) + { + BAIL_MACRO(errcodeFromWinApi(), -1); + } /* if */ + else + { + /* Combine the high/low order to create the 64-bit position value */ + retval = (((PHYSFS_uint64) HighPos) << 32) | LowPos; + assert(retval >= 0); + } /* else */ + + return retval; +} /* __PHYSFS_platformTell */ + + +PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + DWORD SizeHigh; + DWORD SizeLow; + PHYSFS_sint64 retval; + + SizeLow = GetFileSize(Handle, &SizeHigh); + if ( (SizeLow == PHYSFS_INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR) ) + { + BAIL_MACRO(errcodeFromWinApi(), -1); + } /* if */ + else + { + /* Combine the high/low order to create the 64-bit position value */ + retval = (((PHYSFS_uint64) SizeHigh) << 32) | SizeLow; + assert(retval >= 0); + } /* else */ + + return retval; +} /* __PHYSFS_platformFileLength */ + + +int __PHYSFS_platformFlush(void *opaque) +{ + WinApiFile *fh = ((WinApiFile *) opaque); + if (!fh->readonly) + BAIL_IF_MACRO(!FlushFileBuffers(fh->handle), errcodeFromWinApi(), 0); + + return 1; +} /* __PHYSFS_platformFlush */ + + +void __PHYSFS_platformClose(void *opaque) +{ + HANDLE Handle = ((WinApiFile *) opaque)->handle; + (void) CloseHandle(Handle); /* ignore errors. You should have flushed! */ + allocator.Free(opaque); +} /* __PHYSFS_platformClose */ + + +static int doPlatformDelete(LPWSTR wpath) +{ + const int isdir = (GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY); + const BOOL rc = (isdir) ? RemoveDirectoryW(wpath) : DeleteFileW(wpath); + BAIL_IF_MACRO(!rc, errcodeFromWinApi(), 0); + return 1; /* if you made it here, it worked. */ +} /* doPlatformDelete */ + + +int __PHYSFS_platformDelete(const char *path) +{ + int retval = 0; + LPWSTR wpath = NULL; + UTF8_TO_UNICODE_STACK_MACRO(wpath, path); + BAIL_IF_MACRO(!wpath, PHYSFS_ERR_OUT_OF_MEMORY, 0); + retval = doPlatformDelete(wpath); + __PHYSFS_smallFree(wpath); + return retval; +} /* __PHYSFS_platformDelete */ + + +void *__PHYSFS_platformCreateMutex(void) +{ + LPCRITICAL_SECTION lpcs; + lpcs = (LPCRITICAL_SECTION) allocator.Malloc(sizeof (CRITICAL_SECTION)); + BAIL_IF_MACRO(!lpcs, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + InitializeCriticalSection(lpcs); + return lpcs; +} /* __PHYSFS_platformCreateMutex */ + + +void __PHYSFS_platformDestroyMutex(void *mutex) +{ + DeleteCriticalSection((LPCRITICAL_SECTION) mutex); + allocator.Free(mutex); +} /* __PHYSFS_platformDestroyMutex */ + + +int __PHYSFS_platformGrabMutex(void *mutex) +{ + EnterCriticalSection((LPCRITICAL_SECTION) mutex); + return 1; +} /* __PHYSFS_platformGrabMutex */ + + +void __PHYSFS_platformReleaseMutex(void *mutex) +{ + LeaveCriticalSection((LPCRITICAL_SECTION) mutex); +} /* __PHYSFS_platformReleaseMutex */ + + +static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft) +{ + SYSTEMTIME st_utc; + SYSTEMTIME st_localtz; + TIME_ZONE_INFORMATION tzi; + DWORD tzid; + PHYSFS_sint64 retval; + struct tm tm; + BOOL rc; + + BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), errcodeFromWinApi(), -1); + tzid = GetTimeZoneInformation(&tzi); + BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, errcodeFromWinApi(), -1); + rc = SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz); + BAIL_IF_MACRO(!rc, errcodeFromWinApi(), -1); + + /* Convert to a format that mktime() can grok... */ + tm.tm_sec = st_localtz.wSecond; + tm.tm_min = st_localtz.wMinute; + tm.tm_hour = st_localtz.wHour; + tm.tm_mday = st_localtz.wDay; + tm.tm_mon = st_localtz.wMonth - 1; + tm.tm_year = st_localtz.wYear - 1900; + tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/; + tm.tm_yday = -1; + tm.tm_isdst = -1; + + /* Convert to a format PhysicsFS can grok... */ + retval = (PHYSFS_sint64) mktime(&tm); + BAIL_IF_MACRO(retval == -1, PHYSFS_ERR_OS_ERROR, -1); + return retval; +} /* FileTimeToPhysfsTime */ + +int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat) +{ + WIN32_FILE_ATTRIBUTE_DATA winstat; + WCHAR *wstr = NULL; + DWORD err = 0; + BOOL rc = 0; + + UTF8_TO_UNICODE_STACK_MACRO(wstr, filename); + BAIL_IF_MACRO(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0); + rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat); + err = (!rc) ? GetLastError() : 0; + *exists = ((err != ERROR_FILE_NOT_FOUND) && (err != ERROR_PATH_NOT_FOUND)); + __PHYSFS_smallFree(wstr); + BAIL_IF_MACRO(!rc, errcodeFromWinApiError(err), 0); + + stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime); + stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime); + stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime); + + if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + stat->filetype = PHYSFS_FILETYPE_DIRECTORY; + stat->filesize = 0; + } /* if */ + + else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE)) + { + /* !!! FIXME: what are reparse points? */ + stat->filetype = PHYSFS_FILETYPE_OTHER; + /* !!! FIXME: don't rely on this */ + stat->filesize = 0; + } /* else if */ + + /* !!! FIXME: check for symlinks on Vista. */ + + else + { + stat->filetype = PHYSFS_FILETYPE_REGULAR; + stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow; + } /* else */ + + stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0); + + return 1; +} /* __PHYSFS_platformStat */ + + +/* !!! FIXME: Don't use C runtime for allocators? */ +int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a) +{ + return 0; /* just use malloc() and friends. */ +} /* __PHYSFS_platformSetDefaultAllocator */ + +#endif /* PHYSFS_PLATFORM_WINDOWS */ + +/* end of windows.c ... */ + + diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/CMakeLists.txt --- a/misc/quazip/CMakeLists.txt Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -set(QT_USE_QTCORE TRUE) - -find_package(Qt4 REQUIRED) -if(NOT CROSSAPPLE) - include(${QT_USE_FILE}) -endif() - - -file(GLOB SRCS "*.c" "*.cpp") -file(GLOB PUBLIC_HEADERS "*.h") -qt4_wrap_cpp(MOC_SRCS "quazipfile.h") -set(SRCS ${SRCS} ${MOC_SRCS}) - -add_library(quazip STATIC ${SRCS}) diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/JlCompress.cpp --- a/misc/quazip/JlCompress.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,468 +0,0 @@ -#include "JlCompress.h" -#include -/**OK - * Comprime il file fileName, nell'oggetto zip, con il nome fileDest. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip è stato aperto in una modalità non compatibile con l'aggiunta di file; - * * non è possibile aprire il file d'origine; - * * non è possibile creare il file all'interno dell'oggetto zip; - * * si è rilevato un errore nella copia dei dati; - * * non è stato possibile chiudere il file all'interno dell'oggetto zip; - */ -bool JlCompress::compressFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // fileName: nome del file reale - // fileDest: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Apro il file originale - QFile inFile; - inFile.setFileName(fileName); - if(!inFile.open(QIODevice::ReadOnly)) return false; - - // Apro il file risulato - QuaZipFile outFile(zip); - if(!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileDest, inFile.fileName()))) return false; - - // Copio i dati - char c; - while(inFile.getChar(&c)&&outFile.putChar(c)); - if(outFile.getZipError()!=UNZ_OK) return false; - - // Chiudo i file - outFile.close(); - if (outFile.getZipError()!=UNZ_OK) return false; - inFile.close(); - - return true; -} - -/**OK - * Comprime la cartella dir nel file fileCompressed, se recursive è true allora - * comprime anche le sotto cartelle. I nomi dei file preceduti dal path creato - * togliendo il pat della cartella origDir al path della cartella dir. - * Se la funzione fallisce restituisce false e cancella il file che si è tentato - * di creare. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip è stato aperto in una modalità non compatibile con l'aggiunta di file; - * * la cartella dir non esiste; - * * la compressione di una sotto cartella fallisce (1); - * * la compressione di un file fallisce; - * (1) La funzione si richiama in maniera ricorsiva per comprimere le sotto cartelle - * dunque gli errori di compressione di una sotto cartella sono gli stessi di questa - * funzione. - */ -bool JlCompress::compressSubDir(QuaZip* zip, QString dir, QString origDir, bool recursive) { - // zip: oggetto dove aggiungere il file - // dir: cartella reale corrente - // origDir: cartella reale originale - // (path(dir)-path(origDir)) = path interno all'oggetto zip - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdCreate && - zip->getMode()!=QuaZip::mdAppend && - zip->getMode()!=QuaZip::mdAdd) return false; - - // Controllo la cartella - QDir directory(dir); - if (!directory.exists()) return false; - - // Se comprimo anche le sotto cartelle - if (recursive) { - // Per ogni sotto cartella - QFileInfoList files = directory.entryInfoList(QDir::AllDirs|QDir::NoDotAndDotDot); - foreach (QFileInfo file, files) { - // Comprimo la sotto cartella - if(!compressSubDir(zip,file.absoluteFilePath(),origDir,recursive)) return false; - } - } - - // Per ogni file nella cartella - QFileInfoList files = directory.entryInfoList(QDir::Files); - QDir origDirectory(origDir); - foreach (QFileInfo file, files) { - // Se non è un file o è il file compresso che sto creando - if(!file.isFile()||file.absoluteFilePath()==zip->getZipName()) continue; - - // Creo il nome relativo da usare all'interno del file compresso - QString filename = origDirectory.relativeFilePath(file.absoluteFilePath()); - - // Comprimo il file - if (!compressFile(zip,file.absoluteFilePath(),filename)) return false; - } - - return true; -} - -/**OK - * Estrae il file fileName, contenuto nell'oggetto zip, con il nome fileDest. - * Se la funzione fallisce restituisce false e cancella il file che si è tentato di estrarre. - * - * La funzione fallisce se: - * * zip==NULL; - * * l'oggetto zip è stato aperto in una modalità non compatibile con l'estrazione di file; - * * non è possibile aprire il file all'interno dell'oggetto zip; - * * non è possibile creare il file estratto; - * * si è rilevato un errore nella copia dei dati (1); - * * non è stato possibile chiudere il file all'interno dell'oggetto zip (1); - * - * (1): prima di uscire dalla funzione cancella il file estratto. - */ -bool JlCompress::extractFile(QuaZip* zip, QString fileName, QString fileDest) { - // zip: oggetto dove aggiungere il file - // filename: nome del file reale - // fileincompress: nome del file all'interno del file compresso - - // Controllo l'apertura dello zip - if (!zip) return false; - if (zip->getMode()!=QuaZip::mdUnzip) return false; - - // Apro il file compresso - zip->setCurrentFile(fileName); - QuaZipFile inFile(zip); - if(!inFile.open(QIODevice::ReadOnly) || inFile.getZipError()!=UNZ_OK) return false; - - // Controllo esistenza cartella file risultato - QDir().mkpath(QFileInfo(fileDest).absolutePath()); - - // Apro il file risultato - QFile outFile; - outFile.setFileName(fileDest); - if(!outFile.open(QIODevice::WriteOnly)) return false; - - // Copio i dati - char c; - while(inFile.getChar(&c)) outFile.putChar(c); - if (inFile.getZipError()!=UNZ_OK) { - removeFile(QStringList(fileDest)); - return false; - } - - // Chiudo i file - inFile.close(); - if (inFile.getZipError()!=UNZ_OK) { - removeFile(QStringList(fileDest)); - return false; - } - outFile.close(); - - return true; -} - -/** - * Rimuove i file il cui nome è specificato all'interno di listFile. - * Restituisce true se tutti i file sono stati cancellati correttamente, attenzione - * perchè può restituire false anche se alcuni file non esistevano e si è tentato - * di cancellarli. - */ -bool JlCompress::removeFile(QStringList listFile) { - bool ret = true; - // Per ogni file - for (int i=0; iopen(QuaZip::mdCreate)) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - - // Aggiungo il file - if (!compressFile(zip,file,QFileInfo(file).fileName())) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - delete zip; - - return true; -} - -/**OK - * Comprime i file specificati in files nel file fileCompressed. - * Se la funzione fallisce restituisce false e cancella il file che si è tentato - * di creare. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * la compressione di un file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -bool JlCompress::compressFiles(QString fileCompressed, QStringList files) { - // Creo lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); - if(!zip->open(QuaZip::mdCreate)) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - - // Comprimo i file - QFileInfo info; - foreach (QString file, files) { - info.setFile(file); - if (!info.exists() || !compressFile(zip,file,info.fileName())) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - delete zip; - - return true; -} - -/**OK - * Comprime la cartella dir nel file fileCompressed, se recursive è true allora - * comprime anche le sotto cartelle. - * Se la funzione fallisce restituisce false e cancella il file che si è tentato - * di creare. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * la compressione di un file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -bool JlCompress::compressDir(QString fileCompressed, QString dir, bool recursive) { - // Creo lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); - if(!zip->open(QuaZip::mdCreate)) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - - // Aggiungo i file e le sotto cartelle - if (!compressSubDir(zip,dir,dir,recursive)<0) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - QFile::remove(fileCompressed); - return false; - } - delete zip; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/**OK - * Estrae il file fileName, contenuto nel file fileCompressed, con il nome fileDest. - * Se fileDest = "" allora il file viene estratto con lo stesso nome con cui è - * stato compresso. - * Se la funzione fallisce cancella il file che si è tentato di estrarre. - * Restituisce il nome assoluto del file estratto. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * l'estrazione del file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -QString JlCompress::extractFile(QString fileCompressed, QString fileName, QString fileDest) { - // Apro lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - if(!zip->open(QuaZip::mdUnzip)) { - delete zip; - return QString(); - } - - // Estraggo il file - if (fileDest.isEmpty()) fileDest = fileName; - if (!extractFile(zip,fileName,fileDest)) { - delete zip; - return QString(); - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - removeFile(QStringList(fileDest)); - return QString(); - } - delete zip; - - return QFileInfo(fileDest).absoluteFilePath(); -} - -/**OK - * Estrae i file specificati in files, contenuti nel file fileCompressed, nella - * cartella dir. La struttura a cartelle del file compresso viene rispettata. - * Se dir = "" allora il file viene estratto nella cartella corrente. - * Se la funzione fallisce cancella i file che si è tentato di estrarre. - * Restituisce i nomi assoluti dei file estratti. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * l'estrazione di un file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files, QString dir) { - // Creo lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - if(!zip->open(QuaZip::mdUnzip)) { - delete zip; - return QStringList(); - } - - // Estraggo i file - for (int i=0; iclose(); - if(zip->getZipError()!=0) { - delete zip; - removeFile(files); - return QStringList(); - } - delete zip; - - return files; -} - -/**OK - * Estrae il file fileCompressed nella cartella dir. - * Se dir = "" allora il file viene estratto nella cartella corrente. - * Se la funzione fallisce cancella i file che si è tentato di estrarre. - * Restituisce i nomi assoluti dei file estratti. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * la compressione di un file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -QStringList JlCompress::extractDir(QString fileCompressed, QString dir) { - // Apro lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - if(!zip->open(QuaZip::mdUnzip)) { - delete zip; - return QStringList(); - } - - // Estraggo i file - QStringList lst = getFileList(fileCompressed); - - QDir directory(dir); - for (int i=0; iclose(); - if(zip->getZipError()!=0) { - delete zip; - removeFile(lst); - return QStringList(); - } - delete zip; - - return lst; -} - -/**OK - * Restituisce la lista dei file resenti nel file compresso fileCompressed. - * Se la funzione fallisce, restituisce un elenco vuoto. - * - * La funzione fallisce se: - * * non si riesce ad aprire l'oggetto zip; - * * la richiesta di informazioni di un file fallisce; - * * non si riesce a chiudere l'oggetto zip; - */ -QStringList JlCompress::getFileList(QString fileCompressed) { - // Apro lo zip - QuaZip* zip = new QuaZip(QFileInfo(fileCompressed).absoluteFilePath()); - if(!zip->open(QuaZip::mdUnzip)) { - delete zip; - return QStringList(); - } - - // Estraggo i nomi dei file - QStringList lst; - QuaZipFileInfo info; - for(bool more=zip->goToFirstFile(); more; more=zip->goToNextFile()) { - if(!zip->getCurrentFileInfo(&info)) { - delete zip; - return QStringList(); - } - lst << info.name; - //info.name.toLocal8Bit().constData() - } - - // Chiudo il file zip - zip->close(); - if(zip->getZipError()!=0) { - delete zip; - return QStringList(); - } - delete zip; - - return lst; -} - diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/JlCompress.h --- a/misc/quazip/JlCompress.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -#ifndef JLCOMPRESSFOLDER_H_ -#define JLCOMPRESSFOLDER_H_ - -#include "quazip.h" -#include "quazipfile.h" -#include "quazipfileinfo.h" -#include -#include -#include -#include - -class QUAZIP_EXPORT JlCompress { -private: - static bool compressFile(QuaZip* zip, QString fileName, QString fileDest); - static bool compressSubDir(QuaZip* parentZip, QString dir, QString parentDir, bool recursive = true); - static bool extractFile(QuaZip* zip, QString fileName, QString fileDest); - - static bool removeFile(QStringList listFile); - -public: - static bool compressFile(QString fileCompressed, QString file); - static bool compressFiles(QString fileCompressed, QStringList files); - static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true); - -public: - static QString extractFile(QString fileCompressed, QString file, QString fileDest = QString()); - static QStringList extractFiles(QString fileCompressed, QStringList files, QString dir = QString()); - static QStringList extractDir(QString fileCompressed, QString dir = QString()); - static QStringList getFileList(QString fileCompressed); -}; - -#endif /* JLCOMPRESSFOLDER_H_ */ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/crypt.h --- a/misc/quazip/crypt.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* crypt.h -- base code for crypt/uncrypt ZIPfile - - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This code is a modified version of crypting code in Infozip distribution - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - If you don't need crypting in your application, just define symbols - NOCRYPT and NOUNCRYPT. - - This code support the "Traditional PKWARE Encryption". - - The new AES encryption added on Zip format by Winzip (see the page - http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong - Encryption is not supported. -*/ - -#include "quazip_global.h" - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab UNUSED) -{ - //(void) pcrc_32_tab; /* avoid "unused parameter" warning */ - unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an - * unpredictable manner on 16-bit systems; not a problem - * with any known compiler so far, though */ - - temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) -{ - (*(pkeys+0)) = CRC32((*(pkeys+0)), c); - (*(pkeys+1)) += (*(pkeys+0)) & 0xff; - (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; - { - register int keyshift = (int)((*(pkeys+1)) >> 24); - (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); - } - return c; -} - - -/*********************************************************************** - * Initialize the encryption keys and the random header according to - * the given password. - */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) -{ - *(pkeys+0) = 305419896L; - *(pkeys+1) = 591751049L; - *(pkeys+2) = 878082192L; - while (*passwd != '\0') { - update_keys(pkeys,pcrc_32_tab,(int)*passwd); - passwd++; - } -} - -#define zdecode(pkeys,pcrc_32_tab,c) \ - (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) - -#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED - -#define RAND_HEAD_LEN 12 - /* "last resort" source for second part of crypt seed pattern */ -# ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ -# endif - -static int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting) - const char *passwd; /* password string */ - unsigned char *buf; /* where to write header */ - int bufSize; - unsigned long* pkeys; - const unsigned long* pcrc_32_tab; - unsigned long crcForCrypting; -{ - int n; /* index in random header */ - int t; /* temporary */ - int c; /* random byte */ - unsigned char header[RAND_HEAD_LEN-2]; /* random header */ - static unsigned calls = 0; /* ensure different random header each time */ - - if (bufSize> 7) & 0xff; - header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); - } - /* Encrypt random header (last two bytes is high word of crc) */ - init_keys(passwd, pkeys, pcrc_32_tab); - for (n = 0; n < RAND_HEAD_LEN-2; n++) - { - buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); - } - buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/doc/faq.dox --- a/misc/quazip/doc/faq.dox Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/** - * \page faq QuaZip FAQ - * - * - * - * \anchor faq-GPL Q. Is it possible to release an LGPL version of the - * QuaZip? - * - * A. I do not know much about licensing, so I can answer for sure, but - * QuaZip was developed using Open Source edition of Qt, so I see no - * way it could be released under anything except GPL. - * - * \anchor faq-non-QIODevice Q. Is there any way to use QuaZipFile in Qt - * where you are supposed to use normal (non-zipped) file, but not - * through QIODevice API? - * - * A. Usually not. For example, if you are passing file name to some - * database driver (like SQLite), Qt usually just passes this name down - * to the 3rd-party library, which is usually does not know anything - * about QIODevice and therefore there is no way to pass QuaZipFile as - * normal file. However, if we are talking about some place where you - * pass file name, and then indirectly use QFile to open it, then it is - * a good idea to make overloaded method, which accepts QIODevice - * pointer. Then you would be able to pass QuaZipFile as well as many - * other nice things such as QBuffer or QProcess. - **/ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/doc/index.dox --- a/misc/quazip/doc/index.dox Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/** - * \mainpage QuaZIP - Qt/C++ wrapper for ZIP/UNZIP package - * -\htmlonly -Powered by SourceForge.net -\endhtmlonly - * \section overview Overview - * - * QuaZIP is a simple C++ wrapper over Gilles Vollant's ZIP/UNZIP - * package that can be used to access ZIP archives. It uses Trolltech's - * Qt toolkit. - * - * If you do not know what Qt is, you have two options: - * - Just forget about QuaZIP. - * - Learn more about Qt by downloading it and/or reading excellent official Qt documentation - * - * The choice is yours, but if you are really interested in - * cross-platform (Windows/Linux/BSD/UNIX/Mac/Others) software - * development, I would definitely recommend you the second choice ^_^ - * - * QuaZIP allows you to access files inside ZIP archives using QIODevice - * API, and - yes! - that means that you can also use QTextStream, - * QDataStream or whatever you would like to use on your zipped files. - * - * QuaZIP provides complete abstraction of the ZIP/UNZIP API, for both - * reading from and writing to ZIP archives. - * - * \section platforms Platforms supported - * - * QuaZIP has been currently tested with Qt 4.0.0 on the following - * platforms: - * - linux-g++ - * - freebsd-g++ - * - hpux-acc - * - win32-g++ (MinGW) - * - * No testing has been done on other systems. Of course, patches to - * make it work on any platform that it currently does not work on are - * always welcome! - * - * \section whats-new What is new in this version of QuaZIP? - * - * See NEWS file supplied with the distribution. - * - * \section getting Getting latest version of QuaZIP - * - * Check QuaZIP - * project's page at SourceForge.net. Also, you may wish to read - * latest version documentation available at the QuaZIP web site. - * - * \section Requirements - * - * Just zlib and Qt 4. Well, Qt 4 - * depends on zlib anyway. - * - * \section building Building, testing and installing - * - * \note Instructions given in this section assume that you are - * using some UNIX dialect, but the build process should be very similar - * on win32-g++ platform too. Sorry, but other platforms are - * undocumented. I do not think it is a big deal, though - it is - * standard usage of the Qt's qmake, so you most probably already know - * everything that is required. - * - * To build it on some UNIX dialect: -\verbatim -$ cd /wherever/quazip/source/is/quazip-x.y.z/quazip -$ qmake [PREFIX=where-to-install] -$ make -\endverbatim - * - * Make sure that you have Qt 4 installed with all required headers and - * utilities (not just library) and that you run qmake utility of the Qt - * 4, not some other version you may have already installed (you may - * need to type full path to qmake like /usr/local/qt4/bin/qmake). - * - * To reconfigure (with another PREFIX, for example), just run qmake - * with appropriate arguments again. - * - * If you need to specify additional include path or libraries, use - * qmake features (see qmake reference in the Qt documentation). For - * example: - * -\verbatim -$ qmake LIBS+=-L/usr/local/zlib/lib INCLUDEPATH+=/usr/local/zlib/include -\endverbatim - * (note abscence of "-I" before include path) - * - * To check if QuaZIP's basic features work ok on your platform, you may - * wish to compile simple test programs provided in test directory. - * Look in the sources of the tests to find out about their - * requirements. Typically, the test looks something like this: -\verbatim -$ cd /wherever/quazip/source/is/quazip-x.y.z/test/zip -$ qmake -$ make -$ ./zip -$ cd ../unzip -$ cp ../zip/test.zip ./test.zip -$ mkdir out -$ qmake -$ make -$ ./unzip -\endverbatim - * - * You should see the zip contents with details as the output of the - * "./unzip". Ignore message saying you should check the file name for - * testCase() if you do not want to test - * \link QuaZip::CaseSensitivity locale-aware case-insensitivity\endlink. - * Otherwise, see the sources. In any case, this message appearing means - * that everything else was fine. Otherwise, you will get some other error - * message instead. Investigate it or send bug report including message, - * platform and QuaZIP version used. - * - * To install compiled library: -\verbatim -$ make install -\endverbatim - * - * By default, QuaZIP compiles as static library, but you have other - * options: - * - Just copy appropriate source files to your project and use them; - * - Compile QuaZIP as shared library by changing "staticlib" in - * quazip/quazip.pro to "dll". - * - * Latter is not recommended because future versions of QuaZIP most - * probably will be binary incompatible. - * - * \section using Using - * - * See \ref usage "usage page". - * - * \section bugs Bugs - * - * QuaZIP is currently at the initial development stage. Therefore, - * there are may be plenty of bugs and other bad things. Bug reports and - * patches are always welcome (see "contacts" below). - * - * \section contacts Authors and contacts - * - * This wrapper has been written by Sergey A. Tachenov, AKA Alqualos. - * This is my first open source project, so it may suck, but I did not - * find anything like that, so I just had no other choice but to write - * it. - * - * If you have anything to say to me about QuaZIP library, feel free to - * do so (read the \ref faq first, though). I can not promise, - * though, that I fix all the bugs you report in, add any features you - * want, or respond to your critics, or respond to your feedback at all. - * I may be busy, I may be tired of working on QuaZIP, I may be even - * dead already (you never know...). But regardless of this remark, any - * feedback is always welcome. This may seem like a paradox to you, but - * you do not have to understand it to write feedback. - * - * To report bugs or to post ideas about what should be done, use - * SourceForge.net's trackers. - * If you want to send me a private message, use my e-mail address - * laerel at yandex dot ru (but do not you dare to put it somewhere on - * the Web or wherever). - * - * Do not use e-mail to report bugs, please. Reporting bugs and problems - * with the SourceForge.net's bug report system has that advantage that - * it is visible to public. - * - * \section other-projects My other projects - * - * As of this moment, I did not write any other useful open source - * software (well, I am too lazy to do it) except for one little thing: - * - * Arcanum - * universal cap remover. Arcanum is the old but very good game, - * which has one stupid limit: your character maximum level is 50, which - * is too low for many players including me. So I wrote this simple - * patch to increase this stupid limit to something acceptable. - * - * Also, my first Web project, which can be of any interest to you only - * if you can read Russian and you are crazy ^_- This is a web site with - * the main topic of it being The Delirium. It is totally meaningless - * and it was purposely made to be such. Do not ask me why - I do not - * know either. I just did that. If you are interested, then welcome to - * The Brededor. It does not get - * updated lately because I have become even lazier than I ever was. But - * I do not plan to destroy The Brededor no matter what, because I think - * it is fun. - * - * Copyright (C) 2005-2007 Sergey A. Tachenov - **/ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/doc/usage.dox --- a/misc/quazip/doc/usage.dox Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/** \page usage Usage - * - * This page provides general information on QuaZIP usage. See classes - * QuaZip and QuaZipFile for the detailed documentation on what can - * QuaZIP do and what can not. Also, reading comments in the zip.h and - * unzip.h files (taken from the original ZIP/UNZIP package) is always a - * good idea too. After all, QuaZIP is just a wrapper with a few - * convenience extensions and reimplementations. - * - * QuaZip is a class representing ZIP archive, QuaZipFile represents a - * file inside archive and subclasses QIODevice as well. - * - * \section terminology Terminology - * - * "QuaZIP" means whole this library, while "QuaZip" (not case - * difference) is just one class in it. - * - * "ZIP/UNZIP API" means the original API of the Gilles Vollant's - * ZIP/UNZIP package. I did not alter it in any way to make it easier to - * port to the future ZIP/UNZIP versions. - * - * "ZIP", "ZIP archive" or "ZIP file" means any ZIP archive. Typically - * this is a plain file with ".zip" (or ".ZIP") file name suffix. - * - * "A file inside archive", "a file inside ZIP" or something like that - * means file either being read or written from/to some ZIP archive. - * - * \section error-handling Error handling - * - * Almost any call to ZIP/UNZIP API return some error code. Most of the - * original API's error checking could be done in this wrapper as well, - * but it would cause unnecessary code bloating without any benefit. So, - * QuaZIP only checks for situations that ZIP/UNZIP API can not check - * for. For example, ZIP/UNZIP API has no "ZIP open mode" concept - * because read and write modes are completely separated. On the other - * hand, to avoid creating classes like "QuaZipReader", "QuaZipWriter" - * or something like that, QuaZIP introduces "ZIP open mode" concept - * instead, thus making it possible to use one class (QuaZip) for both - * reading and writing. But this leads to additional open mode checks - * which are not done in ZIP/UNZIP package. - * - * Therefore, error checking is two-level (QuaZIP's level and ZIP/UNZIP - * API level), which sometimes can be confusing, so here are some - * advices on how the error checking should be properly done: - * - * - Both QuaZip and QuaZipFile have getZipError() function, which return - * error code of the last ZIP/UNZIP API call. Most function calls - * reset error code to UNZ_OK on success and set error code on - * failure. Some functions do not reset error code. Most of them are - * \c const and do not access ZIP archive in any way. Some, on the - * other hand, \em do access ZIP archive, but do not reset or set - * error code. For example, QuaZipFile::pos() function. Such functions - * are explicitly marked in the documentation. - * - Most functions have its own way to report errors, by returning a - * null string, negative value or \c false. If such a function returns - * error value, call getZipError() to get more information about - * error. See "zip.h" and "unzip.h" of the ZIP/UNZIP package for error - * codes. - * - If the function returns error-stating value (like \c false), but - * getZipError() returns UNZ_OK, it means that you did something - * obviously wrong. For example, tried to write in the archive open - * for reading or not open at all. You better just do not do that! - * Most functions also issue a warning using qWarning() function in - * such cases. See documentation for a specific function for details - * on when it should not be called. - * - * I know that this is somewhat messy, but I could not find a better way - * to do all the error handling. - **/ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/ioapi.h --- a/misc/quazip/ioapi.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -#ifndef _ZLIBIOAPI_H -#define _ZLIBIOAPI_H - - -#define ZLIB_FILEFUNC_SEEK_CUR (1) -#define ZLIB_FILEFUNC_SEEK_END (2) -#define ZLIB_FILEFUNC_SEEK_SET (0) - -#define ZLIB_FILEFUNC_MODE_READ (1) -#define ZLIB_FILEFUNC_MODE_WRITE (2) -#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) - -#define ZLIB_FILEFUNC_MODE_EXISTING (4) -#define ZLIB_FILEFUNC_MODE_CREATE (8) - - -#ifndef ZCALLBACK - -#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) -#define ZCALLBACK CALLBACK -#else -#define ZCALLBACK -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, voidpf file, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef uLong (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell_file_func ztell_file; - seek_file_func zseek_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc_def; - - - -void fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); - -#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) -#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) -#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) -#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) -#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) -#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) - - -#ifdef __cplusplus -} -#endif - -#endif - diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/qioapi.cpp --- a/misc/quazip/qioapi.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* ioapi.c -- IO base function header for compress/uncompress .zip - files using zlib + zip or unzip API - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -#include -#include -#include - -#include "zlib.h" -#include "ioapi.h" -#include "quazip_global.h" -#include - - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -voidpf ZCALLBACK qiodevice_open_file_func ( - voidpf opaque UNUSED, - voidpf file, - int mode) -{ - QIODevice *iodevice = reinterpret_cast(file); - if(iodevice->isSequential()) - return NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - iodevice->open(QIODevice::ReadOnly); - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - iodevice->open(QIODevice::ReadWrite); - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - iodevice->open(QIODevice::WriteOnly); - - if(iodevice->isOpen()) - return iodevice; - else - return NULL; -} - - -uLong ZCALLBACK qiodevice_read_file_func ( - voidpf opaque UNUSED, - voidpf stream, - void* buf, - uLong size) -{ - uLong ret; - ret = (uLong)((QIODevice*)stream)->read((char*)buf,size); - return ret; -} - - -uLong ZCALLBACK qiodevice_write_file_func ( - voidpf opaque UNUSED, - voidpf stream, - const void* buf, - uLong size) -{ - uLong ret; - ret = (uLong)((QIODevice*)stream)->write((char*)buf,size); - return ret; -} - -uLong ZCALLBACK qiodevice_tell_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - uLong ret; - ret = ((QIODevice*)stream)->pos(); - return ret; -} - -int ZCALLBACK qiodevice_seek_file_func ( - voidpf opaque UNUSED, - voidpf stream, - uLong offset, - int origin) -{ - uLong qiodevice_seek_result=0; - int ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - qiodevice_seek_result = ((QIODevice*)stream)->pos() + offset; - break; - case ZLIB_FILEFUNC_SEEK_END : - qiodevice_seek_result = ((QIODevice*)stream)->size() - offset; - break; - case ZLIB_FILEFUNC_SEEK_SET : - qiodevice_seek_result = offset; - break; - default: return -1; - } - ret = !((QIODevice*)stream)->seek(qiodevice_seek_result); - return ret; -} - -int ZCALLBACK qiodevice_close_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - ((QIODevice*)stream)->close(); - return 0; -} - -int ZCALLBACK qiodevice_error_file_func ( - voidpf opaque UNUSED, - voidpf stream) -{ - return !((QIODevice*)stream)->errorString().isEmpty(); -} - -void fill_qiodevice_filefunc ( - zlib_filefunc_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = qiodevice_open_file_func; - pzlib_filefunc_def->zread_file = qiodevice_read_file_func; - pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func; - pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func; - pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func; - pzlib_filefunc_def->zclose_file = qiodevice_close_file_func; - pzlib_filefunc_def->zerror_file = qiodevice_error_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quaadler32.cpp --- a/misc/quazip/quaadler32.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -#include "quaadler32.h" - -#include "zlib.h" - -QuaAdler32::QuaAdler32() -{ - reset(); -} - -quint32 QuaAdler32::calculate(const QByteArray &data) -{ - return adler32( adler32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaAdler32::reset() -{ - checksum = adler32(0L, Z_NULL, 0); -} - -void QuaAdler32::update(const QByteArray &buf) -{ - checksum = adler32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaAdler32::value() -{ - return checksum; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quaadler32.h --- a/misc/quazip/quaadler32.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -#ifndef QUAADLER32_H -#define QUAADLER32_H - -#include - -#include "quachecksum32.h" - -/// Adler32 checksum -/** \class QuaAdler32 quaadler32.h - * This class wrappers the adler32 function with the QuaChecksum32 interface. - * See QuaChecksum32 for more info. - */ -class QuaAdler32 : public QuaChecksum32 -{ - -public: - QuaAdler32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUAADLER32_H diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quachecksum32.h --- a/misc/quazip/quachecksum32.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#ifndef QUACHECKSUM32_H -#define QUACHECKSUM32_H - -#include -#include "quazip_global.h" - -/// Checksum interface. -/** \class QuaChecksum32 quachecksum32.h - * This is an interface for 32 bit checksums. - * Classes implementing this interface can calcunate a certin - * checksum in a single step: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * rasoult = crc32->calculate(data); - * \endcode - * or by streaming the data: - * \code - * QChecksum32 *crc32 = new QuaCrc32(); - * while(!fileA.atEnd()) - * crc32->update(fileA.read(bufSize)); - * resoultA = crc32->value(); - * crc32->reset(); - * while(!fileB.atEnd()) - * crc32->update(fileB.read(bufSize)); - * resoultB = crc32->value(); - * \endcode - */ -class QUAZIP_EXPORT QuaChecksum32 -{ - -public: - ///Calculates the checksum for data. - /** \a data source data - * \return data checksum - * - * This function has no efect on the value returned by value(). - */ - virtual quint32 calculate(const QByteArray &data) = 0; - - ///Resets the calculation on a checksun for a stream. - virtual void reset() = 0; - - ///Updates the calculated checksum for the stream - /** \a buf next portion of data from the stream - */ - virtual void update(const QByteArray &buf) = 0; - - ///Value of the checksum calculated for the stream passed throw update(). - /** \return checksum - */ - virtual quint32 value() = 0; -}; - -#endif //QUACHECKSUM32_H diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quacrc32.cpp --- a/misc/quazip/quacrc32.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -#include "quacrc32.h" - -#include "zlib.h" - -QuaCrc32::QuaCrc32() -{ - reset(); -} - -quint32 QuaCrc32::calculate(const QByteArray &data) -{ - return crc32( crc32(0L, Z_NULL, 0), (const Bytef*)data.data(), data.size() ); -} - -void QuaCrc32::reset() -{ - checksum = crc32(0L, Z_NULL, 0); -} - -void QuaCrc32::update(const QByteArray &buf) -{ - checksum = crc32( checksum, (const Bytef*)buf.data(), buf.size() ); -} - -quint32 QuaCrc32::value() -{ - return checksum; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quacrc32.h --- a/misc/quazip/quacrc32.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -#ifndef QUACRC32_H -#define QUACRC32_H - -#include "quachecksum32.h" - -///CRC32 checksum -/** \class QuaCrc32 quacrc32.h -* This class wrappers the crc32 function with the QuaChecksum32 interface. -* See QuaChecksum32 for more info. -*/ -class QUAZIP_EXPORT QuaCrc32 : public QuaChecksum32 { - -public: - QuaCrc32(); - - quint32 calculate(const QByteArray &data); - - void reset(); - void update(const QByteArray &buf); - quint32 value(); - -private: - quint32 checksum; -}; - -#endif //QUACRC32_H diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazip.cpp --- a/misc/quazip/quazip.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include - -#include "quazip.h" - -class QuaZipPrivate { - friend class QuaZip; - private: - QTextCodec *fileNameCodec, *commentCodec; - QString zipName; - QIODevice *ioDevice; - QString comment; - QuaZip::Mode mode; - union { - unzFile unzFile_f; - zipFile zipFile_f; - }; - bool hasCurrentFile_f; - int zipError; - inline QuaZipPrivate(): - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK) {} - inline QuaZipPrivate(const QString &zipName): - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - zipName(zipName), - ioDevice(NULL), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK) {} - inline QuaZipPrivate(QIODevice *ioDevice): - fileNameCodec(QTextCodec::codecForLocale()), - commentCodec(QTextCodec::codecForLocale()), - ioDevice(ioDevice), - mode(QuaZip::mdNotOpen), - hasCurrentFile_f(false), - zipError(UNZ_OK) {} -}; - -QuaZip::QuaZip(): - p(new QuaZipPrivate()) -{ -} - -QuaZip::QuaZip(const QString& zipName): - p(new QuaZipPrivate(zipName)) -{ -} - -QuaZip::QuaZip(QIODevice *ioDevice): - p(new QuaZipPrivate(ioDevice)) -{ -} - -QuaZip::~QuaZip() -{ - if(isOpen()) - close(); - delete p; -} - -bool QuaZip::open(Mode mode, zlib_filefunc_def* ioApi) -{ - p->zipError=UNZ_OK; - if(isOpen()) { - qWarning("QuaZip::open(): ZIP already opened"); - return false; - } - QIODevice *ioDevice = p->ioDevice; - if (ioDevice == NULL) { - if (p->zipName.isEmpty()) { - qWarning("QuaZip::open(): set either ZIP file name or IO device first"); - return false; - } else { - ioDevice = new QFile(p->zipName); - } - } - switch(mode) { - case mdUnzip: - p->unzFile_f=unzOpen2(ioDevice, ioApi); - if(p->unzFile_f!=NULL) { - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - case mdCreate: - case mdAppend: - case mdAdd: - p->zipFile_f=zipOpen2(ioDevice, - mode==mdCreate?APPEND_STATUS_CREATE: - mode==mdAppend?APPEND_STATUS_CREATEAFTER: - APPEND_STATUS_ADDINZIP, - NULL, - ioApi); - if(p->zipFile_f!=NULL) { - p->mode=mode; - p->ioDevice = ioDevice; - return true; - } else { - p->zipError=UNZ_OPENERROR; - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - } - default: - qWarning("QuaZip::open(): unknown mode: %d", (int)mode); - if (!p->zipName.isEmpty()) - delete ioDevice; - return false; - break; - } -} - -void QuaZip::close() -{ - p->zipError=UNZ_OK; - switch(p->mode) { - case mdNotOpen: - qWarning("QuaZip::close(): ZIP is not open"); - return; - case mdUnzip: - p->zipError=unzClose(p->unzFile_f); - break; - case mdCreate: - case mdAppend: - case mdAdd: - p->zipError=zipClose(p->zipFile_f, p->commentCodec->fromUnicode(p->comment).constData()); - break; - default: - qWarning("QuaZip::close(): unknown mode: %d", (int)p->mode); - return; - } - // opened by name, need to delete the internal IO device - if (!p->zipName.isEmpty()) - delete p->ioDevice; - if(p->zipError==UNZ_OK) - p->mode=mdNotOpen; -} - -void QuaZip::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZip::setZipName(): ZIP is already open!"); - return; - } - p->zipName=zipName; - p->ioDevice = NULL; -} - -void QuaZip::setIoDevice(QIODevice *ioDevice) -{ - if(isOpen()) { - qWarning("QuaZip::setIoDevice(): ZIP is already open!"); - return; - } - p->ioDevice = ioDevice; - p->zipName = QString(); -} - -int QuaZip::getEntriesCount()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getEntriesCount(): ZIP is not open in mdUnzip mode"); - return -1; - } - unz_global_info globalInfo; - if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) - return p->zipError; - return (int)globalInfo.number_entry; -} - -QString QuaZip::getComment()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getComment(): ZIP is not open in mdUnzip mode"); - return QString(); - } - unz_global_info globalInfo; - QByteArray comment; - if((fakeThis->p->zipError=unzGetGlobalInfo(p->unzFile_f, &globalInfo))!=UNZ_OK) - return QString(); - comment.resize(globalInfo.size_comment); - if((fakeThis->p->zipError=unzGetGlobalComment(p->unzFile_f, comment.data(), comment.size())) < 0) - return QString(); - fakeThis->p->zipError = UNZ_OK; - return p->commentCodec->toUnicode(comment); -} - -bool QuaZip::setCurrentFile(const QString& fileName, CaseSensitivity cs) -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::setCurrentFile(): ZIP is not open in mdUnzip mode"); - return false; - } - if(fileName.isEmpty()) { - p->hasCurrentFile_f=false; - return true; - } - // Unicode-aware reimplementation of the unzLocateFile function - if(p->unzFile_f==NULL) { - p->zipError=UNZ_PARAMERROR; - return false; - } - if(fileName.length()>MAX_FILE_NAME_LENGTH) { - p->zipError=UNZ_PARAMERROR; - return false; - } - bool sens; - if(cs==csDefault) { -#ifdef Q_WS_WIN - sens=false; -#else - sens=true; -#endif - } else sens=cs==csSensitive; - QString lower, current; - if(!sens) lower=fileName.toLower(); - p->hasCurrentFile_f=false; - for(bool more=goToFirstFile(); more; more=goToNextFile()) { - current=getCurrentFileName(); - if(current.isEmpty()) return false; - if(sens) { - if(current==fileName) break; - } else { - if(current.toLower()==lower) break; - } - } - return p->hasCurrentFile_f; -} - -bool QuaZip::goToFirstFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToFirstFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::goToNextFile() -{ - p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::goToFirstFile(): ZIP is not open in mdUnzip mode"); - return false; - } - p->zipError=unzGoToNextFile(p->unzFile_f); - p->hasCurrentFile_f=p->zipError==UNZ_OK; - if(p->zipError==UNZ_END_OF_LIST_OF_FILE) - p->zipError=UNZ_OK; - return p->hasCurrentFile_f; -} - -bool QuaZip::getCurrentFileInfo(QuaZipFileInfo *info)const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileInfo(): ZIP is not open in mdUnzip mode"); - return false; - } - unz_file_info info_z; - QByteArray fileName; - QByteArray extra; - QByteArray comment; - if(info==NULL) return false; - if(!isOpen()||!hasCurrentFile()) return false; - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, &info_z, NULL, 0, NULL, 0, NULL, 0))!=UNZ_OK) - return false; - fileName.resize(info_z.size_filename); - extra.resize(info_z.size_file_extra); - comment.resize(info_z.size_file_comment); - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, - fileName.data(), fileName.size(), - extra.data(), extra.size(), - comment.data(), comment.size()))!=UNZ_OK) - return false; - info->versionCreated=info_z.version; - info->versionNeeded=info_z.version_needed; - info->flags=info_z.flag; - info->method=info_z.compression_method; - info->crc=info_z.crc; - info->compressedSize=info_z.compressed_size; - info->uncompressedSize=info_z.uncompressed_size; - info->diskNumberStart=info_z.disk_num_start; - info->internalAttr=info_z.internal_fa; - info->externalAttr=info_z.external_fa; - info->name=p->fileNameCodec->toUnicode(fileName); - info->comment=p->commentCodec->toUnicode(comment); - info->extra=extra; - info->dateTime=QDateTime( - QDate(info_z.tmu_date.tm_year, info_z.tmu_date.tm_mon+1, info_z.tmu_date.tm_mday), - QTime(info_z.tmu_date.tm_hour, info_z.tmu_date.tm_min, info_z.tmu_date.tm_sec)); - return true; -} - -QString QuaZip::getCurrentFileName()const -{ - QuaZip *fakeThis=(QuaZip*)this; // non-const - fakeThis->p->zipError=UNZ_OK; - if(p->mode!=mdUnzip) { - qWarning("QuaZip::getCurrentFileName(): ZIP is not open in mdUnzip mode"); - return QString(); - } - if(!isOpen()||!hasCurrentFile()) return QString(); - QByteArray fileName(MAX_FILE_NAME_LENGTH, 0); - if((fakeThis->p->zipError=unzGetCurrentFileInfo(p->unzFile_f, NULL, fileName.data(), fileName.size(), - NULL, 0, NULL, 0))!=UNZ_OK) - return QString(); - return p->fileNameCodec->toUnicode(fileName.constData()); -} - -void QuaZip::setFileNameCodec(QTextCodec *fileNameCodec) -{ - p->fileNameCodec=fileNameCodec; -} - -void QuaZip::setFileNameCodec(const char *fileNameCodecName) -{ - p->fileNameCodec=QTextCodec::codecForName(fileNameCodecName); -} - -QTextCodec *QuaZip::getFileNameCodec()const -{ - return p->fileNameCodec; -} - -void QuaZip::setCommentCodec(QTextCodec *commentCodec) -{ - p->commentCodec=commentCodec; -} - -void QuaZip::setCommentCodec(const char *commentCodecName) -{ - p->commentCodec=QTextCodec::codecForName(commentCodecName); -} - -QTextCodec *QuaZip::getCommentCodec()const -{ - return p->commentCodec; -} - -QString QuaZip::getZipName() const -{ - return p->zipName; -} - -QIODevice *QuaZip::getIoDevice() const -{ - if (!p->zipName.isEmpty()) // opened by name, using an internal QIODevice - return NULL; - return p->ioDevice; -} - -QuaZip::Mode QuaZip::getMode()const -{ - return p->mode; -} - -bool QuaZip::isOpen()const -{ - return p->mode!=mdNotOpen; -} - -int QuaZip::getZipError() const -{ - return p->zipError; -} - -void QuaZip::setComment(const QString& comment) -{ - p->comment=comment; -} - -bool QuaZip::hasCurrentFile()const -{ - return p->hasCurrentFile_f; -} - -unzFile QuaZip::getUnzFile() -{ - return p->unzFile_f; -} - -zipFile QuaZip::getZipFile() -{ - return p->zipFile_f; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazip.h --- a/misc/quazip/quazip.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,359 +0,0 @@ -#ifndef QUA_ZIP_H -#define QUA_ZIP_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "zip.h" -#include "unzip.h" - -#include "quazip_global.h" -#include "quazipfileinfo.h" - -// just in case it will be defined in the later versions of the ZIP/UNZIP -#ifndef UNZ_OPENERROR -// define additional error code -#define UNZ_OPENERROR -1000 -#endif - -class QuaZipPrivate; - -/// ZIP archive. -/** \class QuaZip quazip.h - * This class implements basic interface to the ZIP archive. It can be - * used to read table contents of the ZIP archive and retreiving - * information about the files inside it. - * - * You can also use this class to open files inside archive by passing - * pointer to the instance of this class to the constructor of the - * QuaZipFile class. But see QuaZipFile::QuaZipFile(QuaZip*, QObject*) - * for the possible pitfalls. - * - * This class is indended to provide interface to the ZIP subpackage of - * the ZIP/UNZIP package as well as to the UNZIP subpackage. But - * currently it supports only UNZIP. - * - * The use of this class is simple - just create instance using - * constructor, then set ZIP archive file name using setFile() function - * (if you did not passed the name to the constructor), then open() and - * then use different functions to work with it! Well, if you are - * paranoid, you may also wish to call close before destructing the - * instance, to check for errors on close. - * - * You may also use getUnzFile() and getZipFile() functions to get the - * ZIP archive handle and use it with ZIP/UNZIP package API directly. - * - * This class supports localized file names inside ZIP archive, but you - * have to set up proper codec with setCodec() function. By default, - * locale codec will be used, which is probably ok for UNIX systems, but - * will almost certainly fail with ZIP archives created in Windows. This - * is because Windows ZIP programs have strange habit of using DOS - * encoding for file names in ZIP archives. For example, ZIP archive - * with cyrillic names created in Windows will have file names in \c - * IBM866 encoding instead of \c WINDOWS-1251. I think that calling one - * function is not much trouble, but for true platform independency it - * would be nice to have some mechanism for file name encoding auto - * detection using locale information. Does anyone know a good way to do - * it? - **/ -class QUAZIP_EXPORT QuaZip { - friend class QuaZipPrivate; - public: - /// Useful constants. - enum Constants { - MAX_FILE_NAME_LENGTH=256 /**< Maximum file name length. Taken from - \c UNZ_MAXFILENAMEINZIP constant in - unzip.c. */ - }; - /// Open mode of the ZIP file. - enum Mode { - mdNotOpen, ///< ZIP file is not open. This is the initial mode. - mdUnzip, ///< ZIP file is open for reading files inside it. - mdCreate, ///< ZIP file was created with open() call. - mdAppend, /**< ZIP file was opened in append mode. This refers to - * \c APPEND_STATUS_CREATEAFTER mode in ZIP/UNZIP package - * and means that zip is appended to some existing file - * what is useful when that file contains - * self-extractor code. This is obviously \em not what - * you whant to use to add files to the existing ZIP - * archive. - **/ - mdAdd ///< ZIP file was opened for adding files in the archive. - }; - /// Case sensitivity for the file names. - /** This is what you specify when accessing files in the archive. - * Works perfectly fine with any characters thanks to Qt's great - * unicode support. This is different from ZIP/UNZIP API, where - * only US-ASCII characters was supported. - **/ - enum CaseSensitivity { - csDefault=0, ///< Default for platform. Case sensitive for UNIX, not for Windows. - csSensitive=1, ///< Case sensitive. - csInsensitive=2 ///< Case insensitive. - }; - private: - QuaZipPrivate *p; - // not (and will not be) implemented - QuaZip(const QuaZip& that); - // not (and will not be) implemented - QuaZip& operator=(const QuaZip& that); - public: - /// Constructs QuaZip object. - /** Call setName() before opening constructed object. */ - QuaZip(); - /// Constructs QuaZip object associated with ZIP file \a zipName. - QuaZip(const QString& zipName); - /// Constructs QuaZip object associated with ZIP file represented by \a ioDevice. - /** The IO device must be seekable, otherwise an error will occur when opening. */ - QuaZip(QIODevice *ioDevice); - /// Destroys QuaZip object. - /** Calls close() if necessary. */ - ~QuaZip(); - /// Opens ZIP file. - /** - * Argument \a mode specifies open mode of the ZIP archive. See Mode - * for details. Note that there is zipOpen2() function in the - * ZIP/UNZIP API which accepts \a globalcomment argument, but it - * does not use it anywhere, so this open() function does not have this - * argument. See setComment() if you need to set global comment. - * - * If the ZIP file is accessed via explicitly set QIODevice, then - * this device is opened in the necessary mode. If the device was - * already opened by some other means, then the behaviour is defined by - * the device implementation, but generally it is not a very good - * idea. For example, QFile will at least issue a warning. - * - * \return \c true if successful, \c false otherwise. - * - * \note ZIP/UNZIP API open calls do not return error code - they - * just return \c NULL indicating an error. But to make things - * easier, quazip.h header defines additional error code \c - * UNZ_ERROROPEN and getZipError() will return it if the open call - * of the ZIP/UNZIP API returns \c NULL. - * - * Argument \a ioApi specifies IO function set for ZIP/UNZIP - * package to use. See unzip.h, zip.h and ioapi.h for details. Note - * that IO API for QuaZip is different from the original package. - * The file path argument was changed to be of type \c voidpf, and - * QuaZip passes a QIODevice pointer there. This QIODevice is either - * set explicitly via setIoDevice() or the QuaZip(QIODevice*) - * constructor, or it is created internally when opening the archive - * by its file name. The default API (qioapi.cpp) just delegates - * everything to the QIODevice API. Not only this allows to use a - * QIODevice instead of file name, but also has a nice side effect - * of raising the file size limit from 2G to 4G. - * - * In short: just forget about the \a ioApi argument and you'll be - * fine. - **/ - bool open(Mode mode, zlib_filefunc_def *ioApi =NULL); - /// Closes ZIP file. - /** Call getZipError() to determine if the close was successful. The - * underlying QIODevice is also closed, regardless of whether it was - * set explicitly or not. */ - void close(); - /// Sets the codec used to encode/decode file names inside archive. - /** This is necessary to access files in the ZIP archive created - * under Windows with non-latin characters in file names. For - * example, file names with cyrillic letters will be in \c IBM866 - * encoding. - **/ - void setFileNameCodec(QTextCodec *fileNameCodec); - /// Sets the codec used to encode/decode file names inside archive. - /** \overload - * Equivalent to calling setFileNameCodec(QTextCodec::codecForName(codecName)); - **/ - void setFileNameCodec(const char *fileNameCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getFileNameCodec() const; - /// Sets the codec used to encode/decode comments inside archive. - /** This codec defaults to locale codec, which is probably ok. - **/ - void setCommentCodec(QTextCodec *commentCodec); - /// Sets the codec used to encode/decode comments inside archive. - /** \overload - * Equivalent to calling setCommentCodec(QTextCodec::codecForName(codecName)); - **/ - void setCommentCodec(const char *commentCodecName); - /// Returns the codec used to encode/decode comments inside archive. - QTextCodec* getCommentCodec() const; - /// Returns the name of the ZIP file. - /** Returns null string if no ZIP file name has been set, for - * example when the QuaZip instance is set up to use a QIODevice - * instead. - * \sa setZipName(), setIoDevice(), getIoDevice() - **/ - QString getZipName() const; - /// Sets the name of the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa setIoDevice(), getIoDevice(), getZipName() - **/ - void setZipName(const QString& zipName); - /// Returns the device representing this ZIP file. - /** Returns null string if no device has been set explicitly, for - * example when opening a ZIP file by name. - * \sa setIoDevice(), getZipName(), setZipName() - **/ - QIODevice *getIoDevice() const; - /// Sets the device representing the ZIP file. - /** Does nothing if the ZIP file is open. - * - * Does not reset error code returned by getZipError(). - * \sa getIoDevice(), getZipName(), setZipName() - **/ - void setIoDevice(QIODevice *ioDevice); - /// Returns the mode in which ZIP file was opened. - Mode getMode() const; - /// Returns \c true if ZIP file is open, \c false otherwise. - bool isOpen() const; - /// Returns the error code of the last operation. - /** Returns \c UNZ_OK if the last operation was successful. - * - * Error code resets to \c UNZ_OK every time you call any function - * that accesses something inside ZIP archive, even if it is \c - * const (like getEntriesCount()). open() and close() calls reset - * error code too. See documentation for the specific functions for - * details on error detection. - **/ - int getZipError() const; - /// Returns number of the entries in the ZIP central directory. - /** Returns negative error code in the case of error. The same error - * code will be returned by subsequent getZipError() call. - **/ - int getEntriesCount() const; - /// Returns global comment in the ZIP file. - QString getComment() const; - /// Sets global comment in the ZIP file. - /** Comment will be written to the archive on close operation. - * - * \sa open() - **/ - void setComment(const QString& comment); - /// Sets the current file to the first file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to get the error code. - **/ - bool goToFirstFile(); - /// Sets the current file to the next file in the archive. - /** Returns \c true on success, \c false otherwise. Call - * getZipError() to determine if there was an error. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \note If the end of file was reached, getZipError() will return - * \c UNZ_OK instead of \c UNZ_END_OF_LIST_OF_FILE. This is to make - * things like this easier: - * \code - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * // do something - * } - * if(zip.getZipError()==UNZ_OK) { - * // ok, there was no error - * } - * \endcode - **/ - bool goToNextFile(); - /// Sets current file by its name. - /** Returns \c true if successful, \c false otherwise. Argument \a - * cs specifies case sensitivity of the file name. Call - * getZipError() in the case of a failure to get error code. - * - * This is not a wrapper to unzLocateFile() function. That is - * because I had to implement locale-specific case-insensitive - * comparison. - * - * Here are the differences from the original implementation: - * - * - If the file was not found, error code is \c UNZ_OK, not \c - * UNZ_END_OF_LIST_OF_FILE (see also goToNextFile()). - * - If this function fails, it unsets the current file rather than - * resetting it back to what it was before the call. - * - * If \a fileName is null string then this function unsets the - * current file and return \c true. Note that you should close the - * file first if it is open! See - * QuaZipFile::QuaZipFile(QuaZip*,QObject*) for the details. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * \sa setFileNameCodec(), CaseSensitivity - **/ - bool setCurrentFile(const QString& fileName, CaseSensitivity cs =csDefault); - /// Returns \c true if the current file has been set. - bool hasCurrentFile() const; - /// Retrieves information about the current file. - /** Fills the structure pointed by \a info. Returns \c true on - * success, \c false otherwise. In the latter case structure pointed - * by \a info remains untouched. If there was an error, - * getZipError() returns error code. - * - * Should be used only in QuaZip::mdUnzip mode. - * - * Does nothing and returns \c false in any of the following cases. - * - ZIP is not open; - * - ZIP does not have current file; - * - \a info is \c NULL; - * - * In all these cases getZipError() returns \c UNZ_OK since there - * is no ZIP/UNZIP API call. - **/ - bool getCurrentFileInfo(QuaZipFileInfo* info)const; - /// Returns the current file name. - /** Equivalent to calling getCurrentFileInfo() and then getting \c - * name field of the QuaZipFileInfo structure, but faster and more - * convenient. - * - * Should be used only in QuaZip::mdUnzip mode. - **/ - QString getCurrentFileName()const; - /// Returns \c unzFile handle. - /** You can use this handle to directly call UNZIP part of the - * ZIP/UNZIP package functions (see unzip.h). - * - * \warning When using the handle returned by this function, please - * keep in mind that QuaZip class is unable to detect any changes - * you make in the ZIP file state (e. g. changing current file, or - * closing the handle). So please do not do anything with this - * handle that is possible to do with the functions of this class. - * Or at least return the handle in the original state before - * calling some another function of this class (including implicit - * destructor calls and calls from the QuaZipFile objects that refer - * to this QuaZip instance!). So if you have changed the current - * file in the ZIP archive - then change it back or you may - * experience some strange behavior or even crashes. - **/ - unzFile getUnzFile(); - /// Returns \c zipFile handle. - /** You can use this handle to directly call ZIP part of the - * ZIP/UNZIP package functions (see zip.h). Warnings about the - * getUnzFile() function also apply to this function. - **/ - zipFile getZipFile(); -}; - -#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazip.pri --- a/misc/quazip/quazip.pri Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD -HEADERS += $$PWD/crypt.h \ - $$PWD/ioapi.h \ - $$PWD/JlCompress.h \ - $$PWD/quaadler32.h \ - $$PWD/quachecksum32.h \ - $$PWD/quacrc32.h \ - $$PWD/quazip.h \ - $$PWD/quazipfile.h \ - $$PWD/quazipfileinfo.h \ - $$PWD/quazipnewinfo.h \ - $$PWD/unzip.h \ - $$PWD/zip.h -SOURCES += $$PWD/qioapi.cpp \ - $$PWD/JlCompress.cpp \ - $$PWD/quaadler32.cpp \ - $$PWD/quacrc32.cpp \ - $$PWD/quazip.cpp \ - $$PWD/quazipfile.cpp \ - $$PWD/quazipnewinfo.cpp \ - $$PWD/unzip.c \ - $$PWD/zip.c diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazip.pro --- a/misc/quazip/quazip.pro Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -TEMPLATE = lib -CONFIG += qt warn_on -QT -= gui -DEPENDPATH += . -INCLUDEPATH += . - -# Input -HEADERS += \ - crypt.h\ - ioapi.h\ - JlCompress.h\ - quaadler32.h\ - quachecksum32.h\ - quacrc32.h\ - quazip.h\ - quazipfile.h\ - quazipfileinfo.h\ - quazipnewinfo.h\ - quazip_global.h\ - unzip.h\ - zip.h\ - -SOURCES += *.c *.cpp - -unix:!symbian { - headers.path=$$PREFIX/include/quazip - headers.files=$$HEADERS - target.path=$$PREFIX/lib - INSTALLS += headers target - - OBJECTS_DIR=.obj - MOC_DIR=.moc - - LIBS += -lz -} - -win32 { - headers.path=$$PREFIX/include/quazip - headers.files=$$HEADERS - target.path=$$PREFIX/lib - INSTALLS += headers target - - *-g++*: LIBS += -lz.dll - *-msvc*: LIBS += -lzlib - *-msvc*: QMAKE_LFLAGS += /IMPLIB:$$DESTDIR\\quazip.lib -} - - -symbian { - - # Note, on Symbian you may run into troubles with LGPL. - # The point is, if your application uses some version of QuaZip, - # and a newer binary compatible version of QuaZip is released, then - # the users of your application must be able to relink it with the - # new QuaZip version. For example, to take advantage of some QuaZip - # bug fixes. - - # This is probably best achieved by building QuaZip as a static - # library and providing linkable object files of your application, - # so users can relink it. - - CONFIG += staticlib - CONFIG += debug_and_release - - LIBS += -lezip - - #Export headers to SDK Epoc32/include directory - exportheaders.sources = $$HEADERS - exportheaders.path = quazip - for(header, exportheaders.sources) { - BLD_INF_RULES.prj_exports += "$$header $$exportheaders.path/$$basename(header)" - } -} - - - -DEFINES += QUAZIP_BUILD diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazip_global.h --- a/misc/quazip/quazip_global.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/** -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - */ - -#ifndef QUAZIP_GLOBAL_H -#define QUAZIP_GLOBAL_H - -#include -/** - * When building the library with MSVC, QUAZIP_BUILD must be defined. - * qglobal.h takes care of defining Q_DECL_* correctly for msvc/gcc. - */ - -#define QUAZIP_EXPORT - -#ifdef __GNUC__ -#define UNUSED __attribute__((__unused__)) -#else -#define UNUSED -#endif - -#endif // QUAZIP_GLOBAL_H diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazipfile.cpp --- a/misc/quazip/quazipfile.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include "quazipfile.h" - -using namespace std; - -class QuaZipFilePrivate { - friend class QuaZipFile; - private: - QuaZipFile *q; - QuaZip *zip; - QString fileName; - QuaZip::CaseSensitivity caseSensitivity; - bool raw; - qint64 writePos; - // these two are for writing raw files - ulong uncompressedSize; - quint32 crc; - bool internal; - int zipError; - inline void resetZipError() const {setZipError(UNZ_OK);} - // const, but sets zipError! - void setZipError(int zipError) const; - inline QuaZipFilePrivate(QuaZipFile *q): - q(q), zip(NULL), internal(true), zipError(UNZ_OK) {} - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName): - q(q), internal(true), zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - } - inline QuaZipFilePrivate(QuaZipFile *q, const QString &zipName, const QString &fileName, - QuaZip::CaseSensitivity cs): - q(q), internal(true), zipError(UNZ_OK) - { - zip=new QuaZip(zipName); - this->fileName=fileName; - this->caseSensitivity=cs; - } - inline QuaZipFilePrivate(QuaZipFile *q, QuaZip *zip): - q(q), zip(zip), internal(false), zipError(UNZ_OK) {} - inline ~QuaZipFilePrivate() - { - if (internal) - delete zip; - } -}; - -QuaZipFile::QuaZipFile(): - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName)) -{ -} - -QuaZipFile::QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zipName, fileName, cs)) -{ -} - -QuaZipFile::QuaZipFile(QuaZip *zip, QObject *parent): - QIODevice(parent), - p(new QuaZipFilePrivate(this, zip)) -{ -} - -QuaZipFile::~QuaZipFile() -{ - if (isOpen()) - close(); - delete p; -} - -QString QuaZipFile::getZipName() const -{ - return p->zip==NULL ? QString() : p->zip->getZipName(); -} - -QString QuaZipFile::getActualFileName()const -{ - p->setZipError(UNZ_OK); - if (p->zip == NULL || (openMode() & WriteOnly)) - return QString(); - QString name=p->zip->getCurrentFileName(); - if(name.isNull()) - p->setZipError(p->zip->getZipError()); - return name; -} - -void QuaZipFile::setZipName(const QString& zipName) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZipName(): file is already open - can not set ZIP name"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=new QuaZip(zipName); - p->internal=true; -} - -void QuaZipFile::setZip(QuaZip *zip) -{ - if(isOpen()) { - qWarning("QuaZipFile::setZip(): file is already open - can not set ZIP"); - return; - } - if(p->zip!=NULL && p->internal) - delete p->zip; - p->zip=zip; - p->fileName=QString(); - p->internal=false; -} - -void QuaZipFile::setFileName(const QString& fileName, QuaZip::CaseSensitivity cs) -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::setFileName(): call setZipName() first"); - return; - } - if(!p->internal) { - qWarning("QuaZipFile::setFileName(): should not be used when not using internal QuaZip"); - return; - } - if(isOpen()) { - qWarning("QuaZipFile::setFileName(): can not set file name for already opened file"); - return; - } - p->fileName=fileName; - p->caseSensitivity=cs; -} - -void QuaZipFilePrivate::setZipError(int zipError) const -{ - QuaZipFilePrivate *fakeThis = const_cast(this); // non-const - fakeThis->zipError=zipError; - if(zipError==UNZ_OK) - q->setErrorString(QString()); - else - q->setErrorString(q->tr("ZIP/UNZIP API error %1").arg(zipError)); -} - -bool QuaZipFile::open(OpenMode mode) -{ - return open(mode, NULL); -} - -bool QuaZipFile::open(OpenMode mode, int *method, int *level, bool raw, const char *password) -{ - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if(mode&Unbuffered) { - qWarning("QuaZipFile::open(): Unbuffered mode is not supported"); - return false; - } - if((mode&ReadOnly)&&!(mode&WriteOnly)) { - if(p->internal) { - if(!p->zip->open(QuaZip::mdUnzip)) { - p->setZipError(p->zip->getZipError()); - return false; - } - if(!p->zip->setCurrentFile(p->fileName, p->caseSensitivity)) { - p->setZipError(p->zip->getZipError()); - p->zip->close(); - return false; - } - } else { - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdUnzip) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - if(!p->zip->hasCurrentFile()) { - qWarning("QuaZipFile::open(): zip does not have current file"); - return false; - } - } - p->setZipError(unzOpenCurrentFile3(p->zip->getUnzFile(), method, level, (int)raw, password)); - if(p->zipError==UNZ_OK) { - setOpenMode(mode); - p->raw=raw; - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::open(OpenMode mode, const QuaZipNewInfo& info, - const char *password, quint32 crc, - int method, int level, bool raw, - int windowBits, int memLevel, int strategy) -{ - zip_fileinfo info_z; - p->resetZipError(); - if(isOpen()) { - qWarning("QuaZipFile::open(): already opened"); - return false; - } - if((mode&WriteOnly)&&!(mode&ReadOnly)) { - if(p->internal) { - qWarning("QuaZipFile::open(): write mode is incompatible with internal QuaZip approach"); - return false; - } - if(p->zip==NULL) { - qWarning("QuaZipFile::open(): zip is NULL"); - return false; - } - if(p->zip->getMode()!=QuaZip::mdCreate&&p->zip->getMode()!=QuaZip::mdAppend&&p->zip->getMode()!=QuaZip::mdAdd) { - qWarning("QuaZipFile::open(): file open mode %d incompatible with ZIP open mode %d", - (int)mode, (int)p->zip->getMode()); - return false; - } - info_z.tmz_date.tm_year=info.dateTime.date().year(); - info_z.tmz_date.tm_mon=info.dateTime.date().month() - 1; - info_z.tmz_date.tm_mday=info.dateTime.date().day(); - info_z.tmz_date.tm_hour=info.dateTime.time().hour(); - info_z.tmz_date.tm_min=info.dateTime.time().minute(); - info_z.tmz_date.tm_sec=info.dateTime.time().second(); - info_z.dosDate = 0; - info_z.internal_fa=(uLong)info.internalAttr; - info_z.external_fa=(uLong)info.externalAttr; - p->setZipError(zipOpenNewFileInZip3(p->zip->getZipFile(), - p->zip->getFileNameCodec()->fromUnicode(info.name).constData(), &info_z, - info.extraLocal.constData(), info.extraLocal.length(), - info.extraGlobal.constData(), info.extraGlobal.length(), - p->zip->getCommentCodec()->fromUnicode(info.comment).constData(), - method, level, (int)raw, - windowBits, memLevel, strategy, - password, (uLong)crc)); - if(p->zipError==UNZ_OK) { - p->writePos=0; - setOpenMode(mode); - p->raw=raw; - if(raw) { - p->crc=crc; - p->uncompressedSize=info.uncompressedSize; - } - return true; - } else - return false; - } - qWarning("QuaZipFile::open(): open mode %d not supported by this function", (int)mode); - return false; -} - -bool QuaZipFile::isSequential()const -{ - return true; -} - -qint64 QuaZipFile::pos()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::pos(): call setZipName() or setZip() first"); - return -1; - } - if(!isOpen()) { - qWarning("QuaZipFile::pos(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - return unztell(p->zip->getUnzFile()); - else - return p->writePos; -} - -bool QuaZipFile::atEnd()const -{ - if(p->zip==NULL) { - qWarning("QuaZipFile::atEnd(): call setZipName() or setZip() first"); - return false; - } - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return false; - } - if(openMode()&ReadOnly) - return unzeof(p->zip->getUnzFile())==1; - else - return true; -} - -qint64 QuaZipFile::size()const -{ - if(!isOpen()) { - qWarning("QuaZipFile::atEnd(): file is not open"); - return -1; - } - if(openMode()&ReadOnly) - return p->raw?csize():usize(); - else - return p->writePos; -} - -qint64 QuaZipFile::csize()const -{ - unz_file_info info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.compressed_size; -} - -qint64 QuaZipFile::usize()const -{ - unz_file_info info_z; - p->setZipError(UNZ_OK); - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return -1; - p->setZipError(unzGetCurrentFileInfo(p->zip->getUnzFile(), &info_z, NULL, 0, NULL, 0, NULL, 0)); - if(p->zipError!=UNZ_OK) - return -1; - return info_z.uncompressed_size; -} - -bool QuaZipFile::getFileInfo(QuaZipFileInfo *info) -{ - if(p->zip==NULL||p->zip->getMode()!=QuaZip::mdUnzip) return false; - p->zip->getCurrentFileInfo(info); - p->setZipError(p->zip->getZipError()); - return p->zipError==UNZ_OK; -} - -void QuaZipFile::close() -{ - p->resetZipError(); - if(p->zip==NULL||!p->zip->isOpen()) return; - if(!isOpen()) { - qWarning("QuaZipFile::close(): file isn't open"); - return; - } - if(openMode()&ReadOnly) - p->setZipError(unzCloseCurrentFile(p->zip->getUnzFile())); - else if(openMode()&WriteOnly) - if(isRaw()) p->setZipError(zipCloseFileInZipRaw(p->zip->getZipFile(), p->uncompressedSize, p->crc)); - else p->setZipError(zipCloseFileInZip(p->zip->getZipFile())); - else { - qWarning("Wrong open mode: %d", (int)openMode()); - return; - } - if(p->zipError==UNZ_OK) setOpenMode(QIODevice::NotOpen); - else return; - if(p->internal) { - p->zip->close(); - p->setZipError(p->zip->getZipError()); - } -} - -qint64 QuaZipFile::readData(char *data, qint64 maxSize) -{ - p->setZipError(UNZ_OK); - qint64 bytesRead=unzReadCurrentFile(p->zip->getUnzFile(), data, (unsigned)maxSize); - if(bytesRead<0) p->setZipError((int)bytesRead); - return bytesRead; -} - -qint64 QuaZipFile::writeData(const char* data, qint64 maxSize) -{ - p->setZipError(ZIP_OK); - p->setZipError(zipWriteInFileInZip(p->zip->getZipFile(), data, (uint)maxSize)); - if(p->zipError!=ZIP_OK) return -1; - else { - p->writePos+=maxSize; - return maxSize; - } -} - -QString QuaZipFile::getFileName() const -{ - return p->fileName; -} - -QuaZip::CaseSensitivity QuaZipFile::getCaseSensitivity() const -{ - return p->caseSensitivity; -} - -bool QuaZipFile::isRaw() const -{ - return p->raw; -} - -int QuaZipFile::getZipError() const -{ - return p->zipError; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazipfile.h --- a/misc/quazip/quazipfile.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,433 +0,0 @@ -#ifndef QUA_ZIPFILE_H -#define QUA_ZIPFILE_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include - -#include "quazip_global.h" -#include "quazip.h" -#include "quazipnewinfo.h" - -class QuaZipFilePrivate; - -/// A file inside ZIP archive. -/** \class QuaZipFile quazipfile.h - * This is the most interesting class. Not only it provides C++ - * interface to the ZIP/UNZIP package, but also integrates it with Qt by - * subclassing QIODevice. This makes possible to access files inside ZIP - * archive using QTextStream or QDataStream, for example. Actually, this - * is the main purpose of the whole QuaZIP library. - * - * You can either use existing QuaZip instance to create instance of - * this class or pass ZIP archive file name to this class, in which case - * it will create internal QuaZip object. See constructors' descriptions - * for details. Writing is only possible with the existing instance. - * - * Note that due to the underlying library's limitation it is not - * possible to use multiple QuaZipFile instances to open several files - * in the same archive at the same time. If you need to write to - * multiple files in parallel, then you should write to temporary files - * first, then pack them all at once when you have finished writing. If - * you need to read multiple files inside the same archive in parallel, - * you should extract them all into a temporary directory first. - * - * \section quazipfile-sequential Sequential or random-access? - * - * At the first thought, QuaZipFile has fixed size, the start and the - * end and should be therefore considered random-access device. But - * there is one major obstacle to making it random-access: ZIP/UNZIP API - * does not support seek() operation and the only way to implement it is - * through reopening the file and re-reading to the required position, - * but this is prohibitively slow. - * - * Therefore, QuaZipFile is considered to be a sequential device. This - * has advantage of availability of the ungetChar() operation (QIODevice - * does not implement it properly for non-sequential devices unless they - * support seek()). Disadvantage is a somewhat strange behaviour of the - * size() and pos() functions. This should be kept in mind while using - * this class. - * - **/ -class QUAZIP_EXPORT QuaZipFile: public QIODevice { - friend class QuaZipFilePrivate; - Q_OBJECT - private: - QuaZipFilePrivate *p; - // these are not supported nor implemented - QuaZipFile(const QuaZipFile& that); - QuaZipFile& operator=(const QuaZipFile& that); - protected: - /// Implementation of the QIODevice::readData(). - qint64 readData(char *data, qint64 maxSize); - /// Implementation of the QIODevice::writeData(). - qint64 writeData(const char *data, qint64 maxSize); - public: - /// Constructs a QuaZipFile instance. - /** You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * You should use setZipName() and setFileName() or setZip() before - * trying to call open() on the constructed object. - **/ - QuaZipFile(QObject *parent); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object and \a - * zipName specifies ZIP archive file name. - * - * You should use setFileName() before trying to call open() on the - * constructed object. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - **/ - QuaZipFile(const QString& zipName, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object, \a - * zipName specifies ZIP archive file name and \a fileName and \a cs - * specify a name of the file to open inside archive. - * - * QuaZipFile constructed by this constructor can be used for read - * only access. Use QuaZipFile(QuaZip*,QObject*) for writing. - * - * \sa QuaZip::setCurrentFile() - **/ - QuaZipFile(const QString& zipName, const QString& fileName, - QuaZip::CaseSensitivity cs =QuaZip::csDefault, QObject *parent =NULL); - /// Constructs a QuaZipFile instance. - /** \a parent argument specifies this object's parent object. - * - * \a zip is the pointer to the existing QuaZip object. This - * QuaZipFile object then can be used to read current file in the - * \a zip or to write to the file inside it. - * - * \warning Using this constructor for reading current file can be - * tricky. Let's take the following example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * zip.setCurrentFile("file-in-archive"); - * QuaZipFile file(&zip); - * file.open(QIODevice::ReadOnly); - * // ok, now we can read from the file - * file.read(somewhere, some); - * zip.setCurrentFile("another-file-in-archive"); // oops... - * QuaZipFile anotherFile(&zip); - * anotherFile.open(QIODevice::ReadOnly); - * anotherFile.read(somewhere, some); // this is still ok... - * file.read(somewhere, some); // and this is NOT - * \endcode - * So, what exactly happens here? When we change current file in the - * \c zip archive, \c file that references it becomes invalid - * (actually, as far as I understand ZIP/UNZIP sources, it becomes - * closed, but QuaZipFile has no means to detect it). - * - * Summary: do not close \c zip object or change its current file as - * long as QuaZipFile is open. Even better - use another constructors - * which create internal QuaZip instances, one per object, and - * therefore do not cause unnecessary trouble. This constructor may - * be useful, though, if you already have a QuaZip instance and do - * not want to access several files at once. Good example: - * \code - * QuaZip zip("archive.zip"); - * zip.open(QuaZip::mdUnzip); - * // first, we need some information about archive itself - * QByteArray comment=zip.getComment(); - * // and now we are going to access files inside it - * QuaZipFile file(&zip); - * for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) { - * file.open(QIODevice::ReadOnly); - * // do something cool with file here - * file.close(); // do not forget to close! - * } - * zip.close(); - * \endcode - **/ - QuaZipFile(QuaZip *zip, QObject *parent =NULL); - /// Destroys a QuaZipFile instance. - /** Closes file if open, destructs internal QuaZip object (if it - * exists and \em is internal, of course). - **/ - virtual ~QuaZipFile(); - /// Returns the ZIP archive file name. - /** If this object was created by passing QuaZip pointer to the - * constructor, this function will return that QuaZip's file name - * (or null string if that object does not have file name yet). - * - * Otherwise, returns associated ZIP archive file name or null - * string if there are no name set yet. - * - * \sa setZipName() getFileName() - **/ - QString getZipName()const; - /// Returns a pointer to the associated QuaZip object. - /** Returns \c NULL if there is no associated QuaZip or it is - * internal (so you will not mess with it). - **/ - QuaZip* getZip()const; - /// Returns file name. - /** This function returns file name you passed to this object either - * by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). Real name of the file may differ in - * case if you used case-insensitivity. - * - * Returns null string if there is no file name set yet. This is the - * case when this QuaZipFile operates on the existing QuaZip object - * (constructor QuaZipFile(QuaZip*,QObject*) or setZip() was used). - * - * \sa getActualFileName - **/ - QString getFileName() const; - /// Returns case sensitivity of the file name. - /** This function returns case sensitivity argument you passed to - * this object either by using - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*) - * or by calling setFileName(). - * - * Returns unpredictable value if getFileName() returns null string - * (this is the case when you did not used setFileName() or - * constructor above). - * - * \sa getFileName - **/ - QuaZip::CaseSensitivity getCaseSensitivity() const; - /// Returns the actual file name in the archive. - /** This is \em not a ZIP archive file name, but a name of file inside - * archive. It is not necessary the same name that you have passed - * to the - * QuaZipFile(const QString&,const QString&,QuaZip::CaseSensitivity,QObject*), - * setFileName() or QuaZip::setCurrentFile() - this is the real file - * name inside archive, so it may differ in case if the file name - * search was case-insensitive. - * - * Equivalent to calling getCurrentFileName() on the associated - * QuaZip object. Returns null string if there is no associated - * QuaZip object or if it does not have a current file yet. And this - * is the case if you called setFileName() but did not open the - * file yet. So this is perfectly fine: - * \code - * QuaZipFile file("somezip.zip"); - * file.setFileName("somefile"); - * QString name=file.getName(); // name=="somefile" - * QString actual=file.getActualFileName(); // actual is null string - * file.open(QIODevice::ReadOnly); - * QString actual=file.getActualFileName(); // actual can be "SoMeFiLe" on Windows - * \endcode - * - * \sa getZipName(), getFileName(), QuaZip::CaseSensitivity - **/ - QString getActualFileName()const; - /// Sets the ZIP archive file name. - /** Automatically creates internal QuaZip object and destroys - * previously created internal QuaZip object, if any. - * - * Will do nothing if this file is already open. You must close() it - * first. - **/ - void setZipName(const QString& zipName); - /// Returns \c true if the file was opened in raw mode. - /** If the file is not open, the returned value is undefined. - * - * \sa open(OpenMode,int*,int*,bool,const char*) - **/ - bool isRaw() const; - /// Binds to the existing QuaZip instance. - /** This function destroys internal QuaZip object, if any, and makes - * this QuaZipFile to use current file in the \a zip object for any - * further operations. See QuaZipFile(QuaZip*,QObject*) for the - * possible pitfalls. - * - * Will do nothing if the file is currently open. You must close() - * it first. - **/ - void setZip(QuaZip *zip); - /// Sets the file name. - /** Will do nothing if at least one of the following conditions is - * met: - * - ZIP name has not been set yet (getZipName() returns null - * string). - * - This QuaZipFile is associated with external QuaZip. In this - * case you should call that QuaZip's setCurrentFile() function - * instead! - * - File is already open so setting the name is meaningless. - * - * \sa QuaZip::setCurrentFile - **/ - void setFileName(const QString& fileName, QuaZip::CaseSensitivity cs =QuaZip::csDefault); - /// Opens a file for reading. - /** Returns \c true on success, \c false otherwise. - * Call getZipError() to get error code. - * - * \note Since ZIP/UNZIP API provides buffered reading only, - * QuaZipFile does not support unbuffered reading. So do not pass - * QIODevice::Unbuffered flag in \a mode, or open will fail. - **/ - virtual bool open(OpenMode mode); - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. If - * it is NULL then this function behaves just like open(OpenMode). - **/ - inline bool open(OpenMode mode, const char *password) - {return open(mode, NULL, NULL, false, password);} - /// Opens a file for reading. - /** \overload - * Argument \a password specifies a password to decrypt the file. - * - * An integers pointed by \a method and \a level will receive codes - * of the compression method and level used. See unzip.h. - * - * If raw is \c true then no decompression is performed. - * - * \a method should not be \c NULL. \a level can be \c NULL if you - * don't want to know the compression level. - **/ - bool open(OpenMode mode, int *method, int *level, bool raw, const char *password =NULL); - /// Opens a file for writing. - /** \a info argument specifies information about file. It should at - * least specify a correct file name. Also, it is a good idea to - * specify correct timestamp (by default, current time will be - * used). See QuaZipNewInfo. - * - * Arguments \a password and \a crc provide necessary information - * for crypting. Note that you should specify both of them if you - * need crypting. If you do not, pass \c NULL as password, but you - * still need to specify \a crc if you are going to use raw mode - * (see below). - * - * Arguments \a method and \a level specify compression method and - * level. - * - * If \a raw is \c true, no compression is performed. In this case, - * \a crc and uncompressedSize field of the \a info are required. - * - * Arguments \a windowBits, \a memLevel, \a strategy provide zlib - * algorithms tuning. See deflateInit2() in zlib. - **/ - bool open(OpenMode mode, const QuaZipNewInfo& info, - const char *password =NULL, quint32 crc =0, - int method =Z_DEFLATED, int level =Z_DEFAULT_COMPRESSION, bool raw =false, - int windowBits =-MAX_WBITS, int memLevel =DEF_MEM_LEVEL, int strategy =Z_DEFAULT_STRATEGY); - /// Returns \c true, but \ref quazipfile-sequential "beware"! - virtual bool isSequential()const; - /// Returns current position in the file. - /** Implementation of the QIODevice::pos(). When reading, this - * function is a wrapper to the ZIP/UNZIP unztell(), therefore it is - * unable to keep track of the ungetChar() calls (which is - * non-virtual and therefore is dangerous to reimplement). So if you - * are using ungetChar() feature of the QIODevice, this function - * reports incorrect value until you get back characters which you - * ungot. - * - * When writing, pos() returns number of bytes already written - * (uncompressed unless you use raw mode). - * - * \note Although - * \ref quazipfile-sequential "QuaZipFile is a sequential device" - * and therefore pos() should always return zero, it does not, - * because it would be misguiding. Keep this in mind. - * - * This function returns -1 if the file or archive is not open. - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual qint64 pos()const; - /// Returns \c true if the end of file was reached. - /** This function returns \c false in the case of error. This means - * that you called this function on either not open file, or a file - * in the not open archive or even on a QuaZipFile instance that - * does not even have QuaZip instance associated. Do not do that - * because there is no means to determine whether \c false is - * returned because of error or because end of file was reached. - * Well, on the other side you may interpret \c false return value - * as "there is no file open to check for end of file and there is - * no end of file therefore". - * - * When writing, this function always returns \c true (because you - * are always writing to the end of file). - * - * Error code returned by getZipError() is not affected by this - * function call. - **/ - virtual bool atEnd()const; - /// Returns file size. - /** This function returns csize() if the file is open for reading in - * raw mode, usize() if it is open for reading in normal mode and - * pos() if it is open for writing. - * - * Returns -1 on error, call getZipError() to get error code. - * - * \note This function returns file size despite that - * \ref quazipfile-sequential "QuaZipFile is considered to be sequential device", - * for which size() should return bytesAvailable() instead. But its - * name would be very misguiding otherwise, so just keep in mind - * this inconsistence. - **/ - virtual qint64 size()const; - /// Returns compressed file size. - /** Equivalent to calling getFileInfo() and then getting - * compressedSize field, but more convenient and faster. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 csize()const; - /// Returns uncompressed file size. - /** Equivalent to calling getFileInfo() and then getting - * uncompressedSize field, but more convenient and faster. See - * getFileInfo() for a warning. - * - * File must be open for reading before calling this function. - * - * Returns -1 on error, call getZipError() to get error code. - **/ - qint64 usize()const; - /// Gets information about current file. - /** This function does the same thing as calling - * QuaZip::getCurrentFileInfo() on the associated QuaZip object, - * but you can not call getCurrentFileInfo() if the associated - * QuaZip is internal (because you do not have access to it), while - * you still can call this function in that case. - * - * File must be open for reading before calling this function. - * - * Returns \c false in the case of an error. - **/ - bool getFileInfo(QuaZipFileInfo *info); - /// Closes the file. - /** Call getZipError() to determine if the close was successful. - **/ - virtual void close(); - /// Returns the error code returned by the last ZIP/UNZIP API call. - int getZipError() const; -}; - -#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazipfileinfo.h --- a/misc/quazip/quazipfileinfo.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -#ifndef QUA_ZIPFILEINFO_H -#define QUA_ZIPFILEINFO_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "quazip_global.h" - -/// Information about a file inside archive. -/** Call QuaZip::getCurrentFileInfo() or QuaZipFile::getFileInfo() to - * fill this structure. */ -struct QUAZIP_EXPORT QuaZipFileInfo { - /// File name. - QString name; - /// Version created by. - quint16 versionCreated; - /// Version needed to extract. - quint16 versionNeeded; - /// General purpose flags. - quint16 flags; - /// Compression method. - quint16 method; - /// Last modification date and time. - QDateTime dateTime; - /// CRC. - quint32 crc; - /// Compressed file size. - quint32 compressedSize; - /// Uncompressed file size. - quint32 uncompressedSize; - /// Disk number start. - quint16 diskNumberStart; - /// Internal file attributes. - quint16 internalAttr; - /// External file attributes. - quint32 externalAttr; - /// Comment. - QString comment; - /// Extra field. - QByteArray extra; -}; - -#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazipnewinfo.cpp --- a/misc/quazip/quazipnewinfo.cpp Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. -*/ - -#include - -#include "quazipnewinfo.h" - - -QuaZipNewInfo::QuaZipNewInfo(const QString& name): - name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0) -{ -} - -QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file): - name(name), internalAttr(0), externalAttr(0) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (!info.exists()) - dateTime = QDateTime::currentDateTime(); - else - dateTime = lm; -} - -void QuaZipNewInfo::setFileDateTime(const QString& file) -{ - QFileInfo info(file); - QDateTime lm = info.lastModified(); - if (info.exists()) - dateTime = lm; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/quazipnewinfo.h --- a/misc/quazip/quazipnewinfo.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#ifndef QUA_ZIPNEWINFO_H -#define QUA_ZIPNEWINFO_H - -/* -Copyright (C) 2005-2011 Sergey A. Tachenov - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2 of the License, or (at -your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -See COPYING file for the full LGPL text. - -Original ZIP package is copyrighted by Gilles Vollant, see -quazip/(un)zip.h files for details, basically it's zlib license. - **/ - -#include -#include - -#include "quazip_global.h" - -/// Information about a file to be created. -/** This structure holds information about a file to be created inside - * ZIP archive. At least name should be set to something correct before - * passing this structure to - * QuaZipFile::open(OpenMode,const QuaZipNewInfo&,int,int,bool). - **/ -struct QUAZIP_EXPORT QuaZipNewInfo { - /// File name. - /** This field holds file name inside archive, including path relative - * to archive root. - **/ - QString name; - /// File timestamp. - /** This is the last file modification date and time. Will be stored - * in the archive central directory. It is a good practice to set it - * to the source file timestamp instead of archive creating time. Use - * setFileDateTime() or QuaZipNewInfo(const QString&, const QString&). - **/ - QDateTime dateTime; - /// File internal attributes. - quint16 internalAttr; - /// File external attributes. - quint32 externalAttr; - /// File comment. - /** Will be encoded using QuaZip::getCommentCodec(). - **/ - QString comment; - /// File local extra field. - QByteArray extraLocal; - /// File global extra field. - QByteArray extraGlobal; - /// Uncompressed file size. - /** This is only needed if you are using raw file zipping mode, i. e. - * adding precompressed file in the zip archive. - **/ - ulong uncompressedSize; - /// Constructs QuaZipNewInfo instance. - /** Initializes name with \a name, dateTime with current date and - * time. Attributes are initialized with zeros, comment and extra - * field with null values. - **/ - QuaZipNewInfo(const QString& name); - /// Constructs QuaZipNewInfo instance. - /** Initializes name with \a name and dateTime with timestamp of the - * file named \a file. If the \a file does not exists or its timestamp - * is inaccessible (e. g. you do not have read permission for the - * directory file in), uses current date and time. Attributes are - * initialized with zeros, comment and extra field with null values. - * - * \sa setFileDateTime() - **/ - QuaZipNewInfo(const QString& name, const QString& file); - /// Sets the file timestamp from the existing file. - /** Use this function to set the file timestamp from the existing - * file. Use it like this: - * \code - * QuaZipFile zipFile(&zip); - * QFile file("file-to-add"); - * file.open(QIODevice::ReadOnly); - * QuaZipNewInfo info("file-name-in-archive"); - * info.setFileDateTime("file-to-add"); // take the timestamp from file - * zipFile.open(QIODevice::WriteOnly, info); - * \endcode - * - * This function does not change dateTime if some error occured (e. g. - * file is inaccessible). - **/ - void setFileDateTime(const QString& file); -}; - -#endif diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/unzip.c --- a/misc/quazip/unzip.c Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1603 +0,0 @@ -/* unzip.c -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - Read unzip.h for more info - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - -/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of -compatibility with older software. The following is from the original crypt.c. Code -woven in by Terry Thorsen 1/2003. -*/ -/* - Copyright (c) 1990-2000 Info-ZIP. All rights reserved. - - See the accompanying file LICENSE, version 2000-Apr-09 or later - (the contents of which are also included in zip.h) for terms of use. - If, for some reason, all these files are missing, the Info-ZIP license - also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html -*/ -/* - crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - */ - -/* - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - */ - - -#include -#include -#include -#include "zlib.h" -#include "unzip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - - -#ifndef CASESENSITIVITYDEFAULT_NO -# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) -# define CASESENSITIVITYDEFAULT_NO -# endif -#endif - - -#ifndef UNZ_BUFSIZE -#define UNZ_BUFSIZE (16384) -#endif - -#ifndef UNZ_MAXFILENAMEINZIP -#define UNZ_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) - - - - -const char unz_copyright[] = - " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info_internal_s -{ - uLong offset_curfile;/* relative offset of local header 4 bytes */ -} unz_file_info_internal; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ - uLong stream_initialised; /* flag set if stream structure is initialised*/ - - uLong offset_local_extrafield;/* offset of the local extra field */ - uInt size_local_extrafield;/* size of the local extra field */ - uLong pos_local_extrafield; /* position in the local extra field in read*/ - - uLong crc32; /* crc32 of all data uncompressed */ - uLong crc32_wait; /* crc32 we must obtain after decompress all */ - uLong rest_read_compressed; /* number of byte to be decompressed */ - uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - uLong compression_method; /* compression method (0==store) */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - int raw; -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - uLong num_file; /* number of the current file in the zipfile*/ - uLong pos_in_central_dir; /* pos of the current file in the central dir*/ - uLong current_file_ok; /* flag about the usability of the current file*/ - uLong central_pos; /* position of the beginning of the central dir*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ - int encrypted; -# ifndef NOUNCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; -# endif -} unz_s; - - -#ifndef NOUNCRYPT -#include "crypt.h" -#endif - -/* =========================================================================== - Read a byte from a gz_stream; update next_in and avail_in. Return EOF - for end of file. - IN assertion: the stream s has been sucessfully opened for reading. -*/ - - -local int unzlocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return UNZ_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return UNZ_ERRNO; - else - return UNZ_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int unzlocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int unzlocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==UNZ_OK) - err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==UNZ_OK) - *pX = x; - else - *pX = 0; - return err; -} - - -/* My own strcmpi / strcasecmp */ -local int strcmpcasenosensitive_internal (fileName1,fileName2) - const char* fileName1; - const char* fileName2; -{ - for (;;) - { - char c1=*(fileName1++); - char c2=*(fileName2++); - if ((c1>='a') && (c1<='z')) - c1 -= 0x20; - if ((c2>='a') && (c2<='z')) - c2 -= 0x20; - if (c1=='\0') - return ((c2=='\0') ? 0 : -1); - if (c2=='\0') - return 1; - if (c1c2) - return 1; - } -} - - -#ifdef CASESENSITIVITYDEFAULT_NO -#define CASESENSITIVITYDEFAULTVALUE 2 -#else -#define CASESENSITIVITYDEFAULTVALUE 1 -#endif - -#ifndef STRCMPCASENOSENTIVEFUNCTION -#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal -#endif - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) - -*/ -extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) - const char* fileName1; - const char* fileName2; - int iCaseSensitivity; -{ - if (iCaseSensitivity==0) - iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; - - if (iCaseSensitivity==1) - return strcmp(fileName1,fileName2); - - return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif - -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong unzlocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer - "zlib/zlib114.zip". - If the zipfile cannot be opened (file doesn't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ -extern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def) - voidpf file; - zlib_filefunc_def* pzlib_filefunc_def; -{ - unz_s us; - unz_s *s; - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - - int err=UNZ_OK; - - if (unz_copyright[0]!=' ') - return NULL; - - if (pzlib_filefunc_def==NULL) - fill_qiodevice_filefunc(&us.z_filefunc); - else - us.z_filefunc = *pzlib_filefunc_def; - - us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, - file, - ZLIB_FILEFUNC_MODE_READ | - ZLIB_FILEFUNC_MODE_EXISTING); - if (us.filestream==NULL) - return NULL; - - central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); - if (central_pos==0) - err=UNZ_ERRNO; - - if (ZSEEK(us.z_filefunc, us.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - /* the signature, already checked */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) - err=UNZ_ERRNO; - - /* number of the disk with the start of the central directory */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) - err=UNZ_ERRNO; - - /* total number of entries in the central dir */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((number_entry_CD!=us.gi.number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=UNZ_BADZIPFILE; - - /* size of the central directory */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) - err=UNZ_ERRNO; - - /* zipfile comment length */ - if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) - err=UNZ_ERRNO; - - if ((central_pospfile_in_zip_read!=NULL) - unzCloseCurrentFile(file); - - ZCLOSE(s->z_filefunc, s->filestream); - TRYFREE(s); - return UNZ_OK; -} - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) - unzFile file; - unz_global_info *pglobal_info; -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - *pglobal_info=s->gi; - return UNZ_OK; -} - - -/* - Translate date/time from Dos format to tm_unz (readable more easilty) -*/ -local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) - uLong ulDosDate; - tm_unz* ptm; -{ - uLong uDate; - uDate = (uLong)(ulDosDate>>16); - ptm->tm_mday = (uInt)(uDate&0x1f) ; - ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; - ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; - - ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); - ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; - ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; -} - -/* - Get Info about the current file in the zipfile, with internal only info -*/ -local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, - unz_file_info *pfile_info, - unz_file_info_internal - *pfile_info_internal, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); - -local int unzlocal_GetCurrentFileInfoInternal (file, - pfile_info, - pfile_info_internal, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - unz_file_info_internal *pfile_info_internal; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - unz_s* s; - unz_file_info file_info; - unz_file_info_internal file_info_internal; - int err=UNZ_OK; - uLong uMagic; - uLong uSeek=0; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (ZSEEK(s->z_filefunc, s->filestream, - s->pos_in_central_dir+s->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - err=UNZ_ERRNO; - - - /* we check the magic */ - if (err==UNZ_OK) { - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x02014b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) - err=UNZ_ERRNO; - - unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) - err=UNZ_ERRNO; - - uSeek+=file_info.size_filename; - if ((err==UNZ_OK) && (szFileName!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_filename0) && (fileNameBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek -= uSizeRead; - } - - - if ((err==UNZ_OK) && (extraField!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_extraz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - uSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek += file_info.size_file_extra - uSizeRead; - } - else - uSeek+=file_info.size_file_extra; - - - if ((err==UNZ_OK) && (szComment!=NULL)) - { - uLong uSizeRead ; - if (file_info.size_file_commentz_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - uSeek=0; - else - err=UNZ_ERRNO; - } - if ((file_info.size_file_comment>0) && (commentBufferSize>0)) - if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) - err=UNZ_ERRNO; - uSeek+=file_info.size_file_comment - uSizeRead; - } - else - uSeek+=file_info.size_file_comment; - - if ((err==UNZ_OK) && (pfile_info!=NULL)) - *pfile_info=file_info; - - if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) - *pfile_info_internal=file_info_internal; - - return err; -} - - - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. -*/ -extern int ZEXPORT unzGetCurrentFileInfo (file, - pfile_info, - szFileName, fileNameBufferSize, - extraField, extraFieldBufferSize, - szComment, commentBufferSize) - unzFile file; - unz_file_info *pfile_info; - char *szFileName; - uLong fileNameBufferSize; - void *extraField; - uLong extraFieldBufferSize; - char *szComment; - uLong commentBufferSize; -{ - return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, - szFileName,fileNameBufferSize, - extraField,extraFieldBufferSize, - szComment,commentBufferSize); -} - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ -extern int ZEXPORT unzGoToFirstFile (file) - unzFile file; -{ - int err=UNZ_OK; - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - s->pos_in_central_dir=s->offset_central_dir; - s->num_file=0; - err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ -extern int ZEXPORT unzGoToNextFile (file) - unzFile file; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ - if (s->num_file+1==s->gi.number_entry) - return UNZ_END_OF_LIST_OF_FILE; - - s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + - s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; - s->num_file++; - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} - - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzipStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ -extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) - unzFile file; - const char *szFileName; - int iCaseSensitivity; -{ - unz_s* s; - int err; - - /* We remember the 'current' position in the file so that we can jump - * back there if we fail. - */ - unz_file_info cur_file_infoSaved; - unz_file_info_internal cur_file_info_internalSaved; - uLong num_fileSaved; - uLong pos_in_central_dirSaved; - - - if (file==NULL) - return UNZ_PARAMERROR; - - if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) - return UNZ_PARAMERROR; - - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - /* Save the current state */ - num_fileSaved = s->num_file; - pos_in_central_dirSaved = s->pos_in_central_dir; - cur_file_infoSaved = s->cur_file_info; - cur_file_info_internalSaved = s->cur_file_info_internal; - - err = unzGoToFirstFile(file); - - while (err == UNZ_OK) - { - char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; - err = unzGetCurrentFileInfo(file,NULL, - szCurrentFileName,sizeof(szCurrentFileName)-1, - NULL,0,NULL,0); - if (err == UNZ_OK) - { - if (unzStringFileNameCompare(szCurrentFileName, - szFileName,iCaseSensitivity)==0) - return UNZ_OK; - err = unzGoToNextFile(file); - } - } - - /* We failed, so restore the state of the 'current file' to where we - * were. - */ - s->num_file = num_fileSaved ; - s->pos_in_central_dir = pos_in_central_dirSaved ; - s->cur_file_info = cur_file_infoSaved; - s->cur_file_info_internal = cur_file_info_internalSaved; - return err; -} - - -/* -/////////////////////////////////////////// -// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) -// I need random access -// -// Further optimization could be realized by adding an ability -// to cache the directory in memory. The goal being a single -// comprehensive file read to put the file I need in a memory. -*/ - -/* -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; // offset in file - uLong num_of_file; // # of file -} unz_file_pos; -*/ - -extern int ZEXPORT unzGetFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_END_OF_LIST_OF_FILE; - - file_pos->pos_in_zip_directory = s->pos_in_central_dir; - file_pos->num_of_file = s->num_file; - - return UNZ_OK; -} - -extern int ZEXPORT unzGoToFilePos(file, file_pos) - unzFile file; - unz_file_pos* file_pos; -{ - unz_s* s; - int err; - - if (file==NULL || file_pos==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - /* jump to the right spot */ - s->pos_in_central_dir = file_pos->pos_in_zip_directory; - s->num_file = file_pos->num_of_file; - - /* set the current file */ - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - /* return results */ - s->current_file_ok = (err == UNZ_OK); - return err; -} - -/* -// Unzip Helper Functions - should be here? -/////////////////////////////////////////// -*/ - -/* - Read the local header of the current zipfile - Check the coherency of the local header and info in the end of central - directory about this file - store in *piSizeVar the size of extra info in local header - (filename and size of extra field data) -*/ -local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, - poffset_local_extrafield, - psize_local_extrafield) - unz_s* s; - uInt* piSizeVar; - uLong *poffset_local_extrafield; - uInt *psize_local_extrafield; -{ - uLong uMagic,uData,uFlags; - uLong size_filename; - uLong size_extra_field; - int err=UNZ_OK; - - *piSizeVar = 0; - *poffset_local_extrafield = 0; - *psize_local_extrafield = 0; - - if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + - s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - - if (err==UNZ_OK) { - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) - err=UNZ_ERRNO; - else if (uMagic!=0x04034b50) - err=UNZ_BADZIPFILE; - } - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; -/* - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) - err=UNZ_BADZIPFILE; -*/ - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) - err=UNZ_ERRNO; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) - err=UNZ_BADZIPFILE; - - if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ - err=UNZ_ERRNO; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && - ((uFlags & 8)==0)) - err=UNZ_BADZIPFILE; - - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) - err=UNZ_ERRNO; - else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) - err=UNZ_BADZIPFILE; - - *piSizeVar += (uInt)size_filename; - - if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) - err=UNZ_ERRNO; - *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + - SIZEZIPLOCALHEADER + size_filename; - *psize_local_extrafield = (uInt)size_extra_field; - - *piSizeVar += (uInt)size_extra_field; - - return err; -} - -/* - Open for reading data the current file in the zipfile. - If there is no error and the file is opened, the return value is UNZ_OK. -*/ -extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) - unzFile file; - int* method; - int* level; - int raw; - const char* password; -{ - int err=UNZ_OK; - uInt iSizeVar; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uLong offset_local_extrafield; /* offset of the local extra field */ - uInt size_local_extrafield; /* size of the local extra field */ -# ifndef NOUNCRYPT - char source[12]; -# else - if (password != NULL) - return UNZ_PARAMERROR; -# endif - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return UNZ_PARAMERROR; - - if (s->pfile_in_zip_read != NULL) - unzCloseCurrentFile(file); - - if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, - &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) - return UNZ_BADZIPFILE; - - pfile_in_zip_read_info = (file_in_zip_read_info_s*) - ALLOC(sizeof(file_in_zip_read_info_s)); - if (pfile_in_zip_read_info==NULL) - return UNZ_INTERNALERROR; - - pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); - pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; - pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; - pfile_in_zip_read_info->pos_local_extrafield=0; - pfile_in_zip_read_info->raw=raw; - - if (pfile_in_zip_read_info->read_buffer==NULL) - { - TRYFREE(pfile_in_zip_read_info); - return UNZ_INTERNALERROR; - } - - pfile_in_zip_read_info->stream_initialised=0; - - if (method!=NULL) - *method = (int)s->cur_file_info.compression_method; - - if (level!=NULL) - { - *level = 6; - switch (s->cur_file_info.flag & 0x06) - { - case 6 : *level = 1; break; - case 4 : *level = 2; break; - case 2 : *level = 9; break; - } - } - - if ((s->cur_file_info.compression_method!=0) && - (s->cur_file_info.compression_method!=Z_DEFLATED)) - err=UNZ_BADZIPFILE; - - pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; - pfile_in_zip_read_info->crc32=0; - pfile_in_zip_read_info->compression_method = - s->cur_file_info.compression_method; - pfile_in_zip_read_info->filestream=s->filestream; - pfile_in_zip_read_info->z_filefunc=s->z_filefunc; - pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; - - pfile_in_zip_read_info->stream.total_out = 0; - - if ((s->cur_file_info.compression_method==Z_DEFLATED) && - (!raw)) - { - pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; - pfile_in_zip_read_info->stream.zfree = (free_func)0; - pfile_in_zip_read_info->stream.opaque = (voidpf)0; - pfile_in_zip_read_info->stream.next_in = (voidpf)0; - pfile_in_zip_read_info->stream.avail_in = 0; - - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) - pfile_in_zip_read_info->stream_initialised=1; - else - { - TRYFREE(pfile_in_zip_read_info); - return err; - } - /* windowBits is passed < 0 to tell that there is no zlib header. - * Note that in this case inflate *requires* an extra "dummy" byte - * after the compressed stream in order to complete decompression and - * return Z_STREAM_END. - * In unzip, i don't wait absolutely Z_STREAM_END because I known the - * size of both compressed and uncompressed data - */ - } - pfile_in_zip_read_info->rest_read_compressed = - s->cur_file_info.compressed_size ; - pfile_in_zip_read_info->rest_read_uncompressed = - s->cur_file_info.uncompressed_size ; - - - pfile_in_zip_read_info->pos_in_zipfile = - s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + - iSizeVar; - - pfile_in_zip_read_info->stream.avail_in = (uInt)0; - - s->pfile_in_zip_read = pfile_in_zip_read_info; - -# ifndef NOUNCRYPT - if (password != NULL) - { - int i; - s->pcrc_32_tab = get_crc_table(); - init_keys(password,s->keys,s->pcrc_32_tab); - if (ZSEEK(s->z_filefunc, s->filestream, - s->pfile_in_zip_read->pos_in_zipfile + - s->pfile_in_zip_read->byte_before_the_zipfile, - SEEK_SET)!=0) - return UNZ_INTERNALERROR; - if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) - return UNZ_INTERNALERROR; - - for (i = 0; i<12; i++) - zdecode(s->keys,s->pcrc_32_tab,source[i]); - - s->pfile_in_zip_read->pos_in_zipfile+=12; - s->encrypted=1; - } -# endif - - - return UNZ_OK; -} - -extern int ZEXPORT unzOpenCurrentFile (file) - unzFile file; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); -} - -extern int ZEXPORT unzOpenCurrentFilePassword (file, password) - unzFile file; - const char* password; -{ - return unzOpenCurrentFile3(file, NULL, NULL, 0, password); -} - -extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) - unzFile file; - int* method; - int* level; - int raw; -{ - return unzOpenCurrentFile3(file, method, level, raw, NULL); -} - -/* - Read bytes from the current file. - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ -extern int ZEXPORT unzReadCurrentFile (file, buf, len) - unzFile file; - voidp buf; - unsigned len; -{ - int err=UNZ_OK; - uInt iRead = 0; - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->read_buffer == NULL)) - return UNZ_END_OF_LIST_OF_FILE; - if (len==0) - return 0; - - pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; - - pfile_in_zip_read_info->stream.avail_out = (uInt)len; - - if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && - (!(pfile_in_zip_read_info->raw))) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_uncompressed; - - if ((len>pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in) && - (pfile_in_zip_read_info->raw)) - pfile_in_zip_read_info->stream.avail_out = - (uInt)pfile_in_zip_read_info->rest_read_compressed+ - pfile_in_zip_read_info->stream.avail_in; - - while (pfile_in_zip_read_info->stream.avail_out>0) - { - if ((pfile_in_zip_read_info->stream.avail_in==0) && - (pfile_in_zip_read_info->rest_read_compressed>0)) - { - uInt uReadThis = UNZ_BUFSIZE; - if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; - if (uReadThis == 0) - return UNZ_EOF; - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->pos_in_zipfile + - pfile_in_zip_read_info->byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->read_buffer, - uReadThis)!=uReadThis) - return UNZ_ERRNO; - - -# ifndef NOUNCRYPT - if(s->encrypted) - { - uInt i; - for(i=0;iread_buffer[i] = - zdecode(s->keys,s->pcrc_32_tab, - pfile_in_zip_read_info->read_buffer[i]); - } -# endif - - - pfile_in_zip_read_info->pos_in_zipfile += uReadThis; - - pfile_in_zip_read_info->rest_read_compressed-=uReadThis; - - pfile_in_zip_read_info->stream.next_in = - (Bytef*)pfile_in_zip_read_info->read_buffer; - pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; - } - - if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) - { - uInt uDoCopy,i ; - - if ((pfile_in_zip_read_info->stream.avail_in == 0) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - return (iRead==0) ? UNZ_EOF : iRead; - - if (pfile_in_zip_read_info->stream.avail_out < - pfile_in_zip_read_info->stream.avail_in) - uDoCopy = pfile_in_zip_read_info->stream.avail_out ; - else - uDoCopy = pfile_in_zip_read_info->stream.avail_in ; - - for (i=0;istream.next_out+i) = - *(pfile_in_zip_read_info->stream.next_in+i); - - pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, - pfile_in_zip_read_info->stream.next_out, - uDoCopy); - pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; - pfile_in_zip_read_info->stream.avail_in -= uDoCopy; - pfile_in_zip_read_info->stream.avail_out -= uDoCopy; - pfile_in_zip_read_info->stream.next_out += uDoCopy; - pfile_in_zip_read_info->stream.next_in += uDoCopy; - pfile_in_zip_read_info->stream.total_out += uDoCopy; - iRead += uDoCopy; - } - else - { - uLong uTotalOutBefore,uTotalOutAfter; - const Bytef *bufBefore; - uLong uOutThis; - int flush=Z_SYNC_FLUSH; - - uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; - bufBefore = pfile_in_zip_read_info->stream.next_out; - - /* - if ((pfile_in_zip_read_info->rest_read_uncompressed == - pfile_in_zip_read_info->stream.avail_out) && - (pfile_in_zip_read_info->rest_read_compressed == 0)) - flush = Z_FINISH; - */ - err=inflate(&pfile_in_zip_read_info->stream,flush); - - if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) - err = Z_DATA_ERROR; - - uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; - uOutThis = uTotalOutAfter-uTotalOutBefore; - - pfile_in_zip_read_info->crc32 = - crc32(pfile_in_zip_read_info->crc32,bufBefore, - (uInt)(uOutThis)); - - pfile_in_zip_read_info->rest_read_uncompressed -= - uOutThis; - - iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); - - if (err==Z_STREAM_END) - return (iRead==0) ? UNZ_EOF : iRead; - if (err!=Z_OK) - break; - } - } - - if (err==Z_OK) - return iRead; - return err; -} - - -/* - Give the current position in uncompressed data -*/ -extern z_off_t ZEXPORT unztell (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - return (z_off_t)pfile_in_zip_read_info->stream.total_out; -} - - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ -extern int ZEXPORT unzeof (file) - unzFile file; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - if (pfile_in_zip_read_info->rest_read_uncompressed == 0) - return 1; - else - return 0; -} - - - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field that can be read - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ -extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) - unzFile file; - voidp buf; - unsigned len; -{ - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - uInt read_now; - uLong size_to_read; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - size_to_read = (pfile_in_zip_read_info->size_local_extrafield - - pfile_in_zip_read_info->pos_local_extrafield); - - if (buf==NULL) - return (int)size_to_read; - - if (len>size_to_read) - read_now = (uInt)size_to_read; - else - read_now = (uInt)len ; - - if (read_now==0) - return 0; - - if (ZSEEK(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - pfile_in_zip_read_info->offset_local_extrafield + - pfile_in_zip_read_info->pos_local_extrafield, - ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (ZREAD(pfile_in_zip_read_info->z_filefunc, - pfile_in_zip_read_info->filestream, - buf,read_now)!=read_now) - return UNZ_ERRNO; - - return (int)read_now; -} - -/* - Close the file in zip opened with unzipOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ -extern int ZEXPORT unzCloseCurrentFile (file) - unzFile file; -{ - int err=UNZ_OK; - - unz_s* s; - file_in_zip_read_info_s* pfile_in_zip_read_info; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - pfile_in_zip_read_info=s->pfile_in_zip_read; - - if (pfile_in_zip_read_info==NULL) - return UNZ_PARAMERROR; - - - if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && - (!pfile_in_zip_read_info->raw)) - { - if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) - err=UNZ_CRCERROR; - } - - - TRYFREE(pfile_in_zip_read_info->read_buffer); - pfile_in_zip_read_info->read_buffer = NULL; - if (pfile_in_zip_read_info->stream_initialised) - inflateEnd(&pfile_in_zip_read_info->stream); - - pfile_in_zip_read_info->stream_initialised = 0; - TRYFREE(pfile_in_zip_read_info); - - s->pfile_in_zip_read=NULL; - - return err; -} - - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ -extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) - unzFile file; - char *szComment; - uLong uSizeBuf; -{ - unz_s* s; - uLong uReadThis ; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - uReadThis = uSizeBuf; - if (uReadThis>s->gi.size_comment) - uReadThis = s->gi.size_comment; - - if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) - return UNZ_ERRNO; - - if (uReadThis>0) - { - *szComment='\0'; - if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) - return UNZ_ERRNO; - } - - if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) - *(szComment+s->gi.size_comment)='\0'; - return (int)uReadThis; -} - -/* Additions by RX '2004 */ -extern uLong ZEXPORT unzGetOffset (file) - unzFile file; -{ - unz_s* s; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - if (!s->current_file_ok) - return 0; - if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) - if (s->num_file==s->gi.number_entry) - return 0; - return s->pos_in_central_dir; -} - -extern int ZEXPORT unzSetOffset (file, pos) - unzFile file; - uLong pos; -{ - unz_s* s; - int err; - - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - s->pos_in_central_dir = pos; - s->num_file = s->gi.number_entry; /* hack */ - err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, - &s->cur_file_info_internal, - NULL,0,NULL,0,NULL,0); - s->current_file_ok = (err == UNZ_OK); - return err; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/unzip.h --- a/misc/quazip/unzip.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,356 +0,0 @@ -/* unzip.h -- IO for uncompress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Modified by Sergey A. Tachenov to integrate with Qt. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#ifndef _unz_H -#define _unz_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef voidp unzFile; -#endif - - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info_s -{ - uLong number_entry; /* total number of entries in - the central dir on this disk */ - uLong size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info_s -{ - uLong version; /* version made by 2 bytes */ - uLong version_needed; /* version needed to extract 2 bytes */ - uLong flag; /* general purpose bit flag 2 bytes */ - uLong compression_method; /* compression method 2 bytes */ - uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ - uLong crc; /* crc-32 4 bytes */ - uLong compressed_size; /* compressed size 4 bytes */ - uLong uncompressed_size; /* uncompressed size 4 bytes */ - uLong size_filename; /* filename length 2 bytes */ - uLong size_file_extra; /* extra field length 2 bytes */ - uLong size_file_comment; /* file comment length 2 bytes */ - - uLong disk_num_start; /* disk number start 2 bytes */ - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ - - tm_unz tmu_date; -} unz_file_info; - -extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, - const char* fileName2, - int iCaseSensitivity)); -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - - -extern unzFile ZEXPORT unzOpen OF((voidpf file)); -/* - Open a Zip file. path contain whatever zopen_file from the IO API - accepts. For Qt implementation it is a pointer to QIODevice, for - fopen() implementation it's a file name. - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern unzFile ZEXPORT unzOpen2 OF((voidpf file, - zlib_filefunc_def* pzlib_filefunc_def)); -/* - Open a Zip file, like unzOpen, but provide a set of file low level API - for read/write the zip file (see ioapi.h) -*/ - -extern int ZEXPORT unzClose OF((unzFile file)); -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, - unz_global_info *pglobal_info)); -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int ZEXPORT unzGetGlobalComment OF((unzFile file, - char *szComment, - uLong uSizeBuf)); -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of byte copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int ZEXPORT unzGoToNextFile OF((unzFile file)); -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int ZEXPORT unzLocateFile OF((unzFile file, - const char *szFileName, - int iCaseSensitivity)); -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -/* ****************************************** */ -/* Ryan supplied functions */ -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_pos_s -{ - uLong pos_in_zip_directory; /* offset in zip file directory */ - uLong num_of_file; /* # of file */ -} unz_file_pos; - -extern int ZEXPORT unzGetFilePos( - unzFile file, - unz_file_pos* file_pos); - -extern int ZEXPORT unzGoToFilePos( - unzFile file, - unz_file_pos* file_pos); - -/* ****************************************** */ - -extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, - unz_file_info *pfile_info, - char *szFileName, - uLong fileNameBufferSize, - void *extraField, - uLong extraFieldBufferSize, - char *szComment, - uLong commentBufferSize)); -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, - const char* password)); -/* - Open for reading data the current file in the zipfile. - password is a crypting password - If there is no error, the return value is UNZ_OK. -*/ - -extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, - int* method, - int* level, - int raw)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - -extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, - int* method, - int* level, - int raw, - const char* password)); -/* - Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) - if raw==1 - *method will receive method of compression, *level will receive level of - compression - note : you can set level parameter as NULL (if you did not want known level, - but you CANNOT set method parameter as NULL -*/ - - -extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - -extern int ZEXPORT unzReadCurrentFile OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read bytes from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of byte copied if somes bytes are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern z_off_t ZEXPORT unztell OF((unzFile file)); -/* - Give the current position in uncompressed data -*/ - -extern int ZEXPORT unzeof OF((unzFile file)); -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, - voidp buf, - unsigned len)); -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of bytes copied in buf, or (if <0) - the error code -*/ - -/***************************************************************************/ - -/* Get the current file offset */ -extern uLong ZEXPORT unzGetOffset (unzFile file); - -/* Set the current file offset */ -extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _unz_H */ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/zconf.h --- a/misc/quazip/zconf.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,332 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ -# define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams -# define deflateBound z_deflateBound -# define deflatePrime z_deflatePrime -# define inflateInit2_ z_inflateInit2_ -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table -# define zError z_zError - -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func -# define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong -# define Bytef z_Bytef -# define charf z_charf -# define intf z_intf -# define uIntf z_uIntf -# define uLongf z_uLongf -# define voidpf z_voidpf -# define voidp z_voidp -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ -# endif -# define z_off_t off_t -#endif -#ifndef SEEK_SET -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif -#ifndef z_off_t -# define z_off_t long -#endif - -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/zip.c --- a/misc/quazip/zip.c Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1243 +0,0 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.01e, February 12th, 2005 - - 27 Dec 2004 Rolf Kalbermatter - Modification to zipOpen2 to support globalComment retrieval. - - Copyright (C) 1998-2005 Gilles Vollant - - Read zip.h for more info - - Modified by Sergey A. Tachenov to integrate with Qt. -*/ - - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" -#include "quazip_global.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x031e) /* best for standard pkware crypt */ -#endif - -#ifndef Z_BUFSIZE -#define Z_BUFSIZE (16384) -#endif - -#ifndef Z_MAXFILENAMEINZIP -#define Z_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -/* -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) -*/ - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef DEF_MEM_LEVEL -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -#endif -const char zip_copyright[] = - " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define LOCALHEADERMAGIC (0x04034b50) -#define DESCRIPTORHEADERMAGIC (0x08074b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ - -typedef struct linkedlist_datablock_internal_s -{ - struct linkedlist_datablock_internal_s* next_datablock; - uLong avail_in_this_block; - uLong filled_in_this_block; - uLong unused; /* for future use and alignement */ - unsigned char data[SIZEDATA_INDATABLOCK]; -} linkedlist_datablock_internal; - -typedef struct linkedlist_data_s -{ - linkedlist_datablock_internal* first_block; - linkedlist_datablock_internal* last_block; -} linkedlist_data; - - -typedef struct -{ - z_stream stream; /* zLib stream structure for inflate */ - int stream_initialised; /* 1 is stream is initialised */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - uLong pos_local_header; /* offset of the local header of the file - currenty writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralheader; /* size of the central header for cur file */ - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method of file currenty wr.*/ - int raw; /* 1 for directly writing raw data */ - Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ - uLong dosDate; - uLong crc32; - int encrypt; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile_info; - -typedef struct -{ - zlib_filefunc_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - linkedlist_data central_dir;/* datablock with central dir in construction*/ - int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - curfile_info ci; /* info on the file curretly writing */ - - uLong begin_pos; /* position of the beginning of the zipfile */ - uLong add_position_when_writting_offset; - uLong number_entry; -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif -} zip_internal; - - - -#ifndef NOCRYPT -#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -#include "crypt.h" -#endif - -local linkedlist_datablock_internal* allocate_new_datablock() -{ - linkedlist_datablock_internal* ldi; - ldi = (linkedlist_datablock_internal*) - ALLOC(sizeof(linkedlist_datablock_internal)); - if (ldi!=NULL) - { - ldi->next_datablock = NULL ; - ldi->filled_in_this_block = 0 ; - ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; - } - return ldi; -} - -local void free_datablock(ldi) - linkedlist_datablock_internal* ldi; -{ - while (ldi!=NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -local void init_linkedlist(ll) - linkedlist_data* ll; -{ - ll->first_block = ll->last_block = NULL; -} - -#if 0 // unused -local void free_linkedlist(ll) - linkedlist_data* ll; -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} -#endif - -local int add_data_in_datablock(ll,buf,len) - linkedlist_data* ll; - const void* buf; - uLong len; -{ - linkedlist_datablock_internal* ldi; - const unsigned char* from_copy; - - if (ll==NULL) - return ZIP_INTERNALERROR; - - if (ll->last_block == NULL) - { - ll->first_block = ll->last_block = allocate_new_datablock(); - if (ll->first_block == NULL) - return ZIP_INTERNALERROR; - } - - ldi = ll->last_block; - from_copy = (unsigned char*)buf; - - while (len>0) - { - uInt copy_this; - uInt i; - unsigned char* to_copy; - - if (ldi->avail_in_this_block==0) - { - ldi->next_datablock = allocate_new_datablock(); - if (ldi->next_datablock == NULL) - return ZIP_INTERNALERROR; - ldi = ldi->next_datablock ; - ll->last_block = ldi; - } - - if (ldi->avail_in_this_block < len) - copy_this = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - - - -/****************************************************************************/ - -#ifndef NO_ADDFILEINEXISTINGZIP -/* =========================================================================== - Inputs a long in LSB order to the given file - nbByte == 1, 2 or 4 (byte, short or long) -*/ - -local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, uLong x, int nbByte)); -local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong x; - int nbByte; -{ - unsigned char buf[4]; - int n; - for (n = 0; n < nbByte; n++) - { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - if (x != 0) - { /* data overflow - hack for ZIP64 (X Roche) */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } - - if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - else - return ZIP_OK; -} - -local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); -local void ziplocal_putValue_inmemory (dest, x, nbByte) - void* dest; - uLong x; - int nbByte; -{ - unsigned char* buf=(unsigned char*)dest; - int n; - for (n = 0; n < nbByte; n++) { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - - if (x != 0) - { /* data overflow - hack for ZIP64 */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } -} - -/****************************************************************************/ - - -local uLong ziplocal_TmzDateToDosDate(ptm,dosDate) - const tm_zip* ptm; - uLong dosDate UNUSED; -{ - uLong year = (uLong)ptm->tm_year; - if (year>1980) - year-=1980; - else if (year>80) - year-=80; - return - (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); -} - - -/****************************************************************************/ - -local int ziplocal_getByte OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - int *pi)); - -local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - int *pi; -{ - unsigned char c; - int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return ZIP_OK; - } - else - { - if (ZERROR(*pzlib_filefunc_def,filestream)) - return ZIP_ERRNO; - else - return ZIP_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int ziplocal_getShort OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int ziplocal_getLong OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream, - uLong *pX)); - -local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; - uLong *pX; -{ - uLong x ; - int i; - int err; - - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==ZIP_OK) - err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local uLong ziplocal_SearchCentralDir OF(( - const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream)); - -local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream) - const zlib_filefunc_def* pzlib_filefunc_def; - voidpf filestream; -{ - unsigned char* buf; - uLong uSizeFile; - uLong uBackRead; - uLong uMaxBack=0xffff; /* maximum size of global comment */ - uLong uPosFound=0; - - if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); - if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} -#endif /* !NO_ADDFILEINEXISTINGZIP*/ - -/************************************************************/ -extern zipFile ZEXPORT zipOpen2 (file, append, globalcomment, pzlib_filefunc_def) - voidpf file; - int append; - zipcharpc* globalcomment; - zlib_filefunc_def* pzlib_filefunc_def; -{ - zip_internal ziinit; - zip_internal* zi; - int err=ZIP_OK; - - - if (pzlib_filefunc_def==NULL) - fill_qiodevice_filefunc(&ziinit.z_filefunc); - else - ziinit.z_filefunc = *pzlib_filefunc_def; - - ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) - (ziinit.z_filefunc.opaque, - file, - (append == APPEND_STATUS_CREATE) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); - - if (ziinit.filestream == NULL) - return NULL; - ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); - ziinit.in_opened_file_inzip = 0; - ziinit.ci.stream_initialised = 0; - ziinit.number_entry = 0; - ziinit.add_position_when_writting_offset = 0; - init_linkedlist(&(ziinit.central_dir)); - - - zi = (zip_internal*)ALLOC(sizeof(zip_internal)); - if (zi==NULL) - { - ZCLOSE(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - - /* now we add file in a zipfile */ -# ifndef NO_ADDFILEINEXISTINGZIP - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - - uLong size_central_dir; /* size of the central directory */ - uLong offset_central_dir; /* offset of start of central directory */ - uLong central_pos,uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - uLong number_entry; - uLong number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - uLong size_comment; - - central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); - if (central_pos==0) - err=ZIP_ERRNO; - - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir on this disk */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((number_entry_CD!=number_entry) || - (number_disk_with_CD!=0) || - (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* zipfile global comment length */ - if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((central_pos0) - { - ziinit.globalcomment = ALLOC(size_comment+1); - if (ziinit.globalcomment) - { - size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); - ziinit.globalcomment[size_comment]=0; - } - } - - byte_before_the_zipfile = central_pos - - (offset_central_dir+size_central_dir); - ziinit.add_position_when_writting_offset = byte_before_the_zipfile; - - { - uLong size_central_dir_to_read = size_central_dir; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read = (void*)ALLOC(buf_size); - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir + byte_before_the_zipfile, - ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - while ((size_central_dir_to_read>0) && (err==ZIP_OK)) - { - uLong read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) - err=ZIP_ERRNO; - - if (err==ZIP_OK) - err = add_data_in_datablock(&ziinit.central_dir,buf_read, - (uLong)read_this); - size_central_dir_to_read-=read_this; - } - TRYFREE(buf_read); - } - ziinit.begin_pos = byte_before_the_zipfile; - ziinit.number_entry = number_entry_CD; - - if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, - offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - } - - if (globalcomment) - { - *globalcomment = ziinit.globalcomment; - } -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - - if (err != ZIP_OK) - { -# ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); - return NULL; - } - else - { - *zi = ziinit; - return (zipFile)zi; - } -} - -extern zipFile ZEXPORT zipOpen (file, append) - voidpf file; - int append; -{ - return zipOpen2(file,append,NULL,NULL); -} - -extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; - int windowBits; - int memLevel; - int strategy; - const char* password; - uLong crcForCrypting; -{ - zip_internal* zi; - uInt size_filename; - uInt size_comment; - uInt i; - int err = ZIP_OK; - -# ifdef NOCRYPT - if (password != NULL) - return ZIP_PARAMERROR; -# endif - - if (file == NULL) - return ZIP_PARAMERROR; - if ((method!=0) && (method!=Z_DEFLATED)) - return ZIP_PARAMERROR; - - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - - if (filename==NULL) - filename="-"; - - if (comment==NULL) - size_comment = 0; - else - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); - } - - zi->ci.flag = 0; - if ((level==8) || (level==9)) - zi->ci.flag |= 2; - if ((level==2)) - zi->ci.flag |= 4; - if ((level==1)) - zi->ci.flag |= 6; - if (password != NULL) - { - zi->ci.flag |= 1; - } - zi->ci.flag |= 8; - zi->ci.crc32 = 0; - zi->ci.method = method; - zi->ci.encrypt = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + - size_extrafield_global + size_comment; - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); - - ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); - /* version info */ - ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); - ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); - ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); - ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); - ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); - ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ - ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); - ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); - ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); - ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); - else - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); - - if (zipfi==NULL) - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); - else - ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); - - ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); - - for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = - *(((const char*)extrafield_global)+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ - size_extrafield_global+i) = *(comment+i); - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - /* write the local header */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); - - if ((err==ZIP_OK) && (size_filename>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) - err = ZIP_ERRNO; - - if ((err==ZIP_OK) && (size_extrafield_local>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) - !=size_extrafield_local) - err = ZIP_ERRNO; - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)0; - - if (windowBits>0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, - Z_DEFLATED, windowBits, memLevel, strategy); - - if (err==Z_OK) - zi->ci.stream_initialised = 1; - } -# ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err==Z_OK) && (password != NULL)) - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - zi->ci.encrypt = 1; - zi->ci.pcrc_32_tab = get_crc_table(); - /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ - - crcForCrypting = (uLong)zi->ci.dosDate << 16; // ATTANTION! Without this row, you don't unpack your password protected archive in other app. - - sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) - err = ZIP_ERRNO; - } -# endif - - if (err==Z_OK) - zi->in_opened_file_inzip = 1; - return err; -} - -extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; - int raw; -{ - return zipOpenNewFileInZip3 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level) - zipFile file; - const char* filename; - const zip_fileinfo* zipfi; - const void* extrafield_local; - uInt size_extrafield_local; - const void* extrafield_global; - uInt size_extrafield_global; - const char* comment; - int method; - int level; -{ - return zipOpenNewFileInZip2 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0); -} - -local int zipFlushWriteBuffer(zi) - zip_internal* zi; -{ - int err=ZIP_OK; - - if (zi->ci.encrypt != 0) - { -#ifndef NOCRYPT - uInt i; - int t; - for (i=0;ici.pos_in_buffered_data;i++) - zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, - zi->ci.buffered_data[i],t); -#endif - } - if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) - !=zi->ci.pos_in_buffered_data) - err = ZIP_ERRNO; - zi->ci.pos_in_buffered_data = 0; - return err; -} - -extern int ZEXPORT zipWriteInFileInZip (file, buf, len) - zipFile file; - const void* buf; - unsigned len; -{ - zip_internal* zi; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.stream.next_in = (void*)buf; - zi->ci.stream.avail_in = len; - zi->ci.crc32 = crc32(zi->ci.crc32,buf,len); - - while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - - if(err != ZIP_OK) - break; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_NO_FLUSH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - - } - else - { - uInt copy_this,i; - if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) - copy_this = zi->ci.stream.avail_in; - else - copy_this = zi->ci.stream.avail_out; - for (i=0;ici.stream.next_out)+i) = - *(((const char*)zi->ci.stream.next_in)+i); - { - zi->ci.stream.avail_in -= copy_this; - zi->ci.stream.avail_out-= copy_this; - zi->ci.stream.next_in+= copy_this; - zi->ci.stream.next_out+= copy_this; - zi->ci.stream.total_in+= copy_this; - zi->ci.stream.total_out+= copy_this; - zi->ci.pos_in_buffered_data += copy_this; - } - } - } - - return err; -} - -extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32) - zipFile file; - uLong uncompressed_size; - uLong crc32; -{ - zip_internal* zi; - uLong compressed_size; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - while (err==ZIP_OK) - { - uLong uTotalOutBefore; - if (zi->ci.stream.avail_out == 0) - { - if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - - if (err==Z_STREAM_END) - err=ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) - if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) - err = ZIP_ERRNO; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - err=deflateEnd(&zi->ci.stream); - zi->ci.stream_initialised = 0; - } - - if (!zi->ci.raw) - { - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = (uLong)zi->ci.stream.total_in; - } - compressed_size = (uLong)zi->ci.stream.total_out; -# ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -# endif - - ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ - ziplocal_putValue_inmemory(zi->ci.central_header+20, - compressed_size,4); /*compr size*/ - if (zi->ci.stream.data_type == Z_ASCII) - ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); - ziplocal_putValue_inmemory(zi->ci.central_header+24, - uncompressed_size,4); /*uncompr size*/ - - if (err==ZIP_OK) - err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, - (uLong)zi->ci.size_centralheader); - free(zi->ci.central_header); - - if (err==ZIP_OK) - { - uLong cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); - if (ZSEEK(zi->z_filefunc,zi->filestream, - zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if (err==ZIP_OK) /* compressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - - if (ZSEEK(zi->z_filefunc,zi->filestream, - cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - /* Write local Descriptor after file data */ - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)DESCRIPTORHEADERMAGIC,4); - - if (err==ZIP_OK) - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if (err==ZIP_OK) /* compressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - - - } - - zi->number_entry ++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip (file) - zipFile file; -{ - return zipCloseFileInZipRaw (file,0,0); -} - -extern int ZEXPORT zipClose (file, global_comment) - zipFile file; - const char* global_comment; -{ - zip_internal* zi; - int err = 0; - uLong size_centraldir = 0; - uLong centraldir_pos_inzip; - uInt size_global_comment; - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - } - -#ifndef NO_ADDFILEINEXISTINGZIP - if (global_comment==NULL) - global_comment = zi->globalcomment; -#endif - if (global_comment==NULL) - size_global_comment = 0; - else - size_global_comment = (uInt)strlen(global_comment); - - centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); - if (err==ZIP_OK) - { - linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; - while (ldi!=NULL) - { - if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - ldi->data,ldi->filled_in_this_block) - !=ldi->filled_in_this_block ) - err = ZIP_ERRNO; - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - free_datablock(zi->central_dir.first_block); - - if (err==ZIP_OK) /* Magic End */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* number of this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* total number of entries in the central dir */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - - if (err==ZIP_OK) /* size of the central directory */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the - starting disk number */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, - (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); - - if (err==ZIP_OK) /* zipfile comment length */ - err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); - - if ((err==ZIP_OK) && (size_global_comment>0)) - if (ZWRITE(zi->z_filefunc,zi->filestream, - global_comment,size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - - if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/zip.h --- a/misc/quazip/zip.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,237 +0,0 @@ -/* zip.h -- IO for compress .zip files using zlib - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This unzip package allow creates .ZIP file, compatible with PKZip 2.04g - WinZip, InfoZip tools and compatible. - Multi volume ZipFile (span) are not supported. - Encryption compatible with pkzip 2.04g only supported - Old compressions used by old PKZip 1.x are not supported - - For uncompress .zip file, look at unzip.h - - - I WAIT FEEDBACK at mail info@winimage.com - Visit also http://www.winimage.com/zLibDll/unzip.html for evolution - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Modified by Sergey A. Tachenov to integrate with Qt. - - -*/ - -/* for more info about .ZIP format, see - http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip - http://www.info-zip.org/pub/infozip/doc/ - PkWare has also a specification at : - ftp://ftp.pkware.com/probdesc.zip -*/ - -#ifndef _zip_H -#define _zip_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagzipFile__ { int unused; } zipFile__; -typedef zipFile__ *zipFile; -#else -typedef voidp zipFile; -#endif - -#define ZIP_OK (0) -#define ZIP_EOF (0) -#define ZIP_ERRNO (Z_ERRNO) -#define ZIP_PARAMERROR (-102) -#define ZIP_BADZIPFILE (-103) -#define ZIP_INTERNALERROR (-104) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif -/* default memLevel */ - -/* tm_zip contain date/time info */ -typedef struct tm_zip_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_zip; - -typedef struct -{ - tm_zip tmz_date; /* date in understandable format */ - uLong dosDate; /* if dos_date == 0, tmu_date is used */ -/* uLong flag; */ /* general purpose bit flag 2 bytes */ - - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -extern zipFile ZEXPORT zipOpen OF((voidpf file, int append)); -/* - Create a zipfile. - file is whatever the IO API accepts. For Qt IO API it's a pointer to - QIODevice. For fopen() IO API it's a file name (const char*). - if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip - will be created at the end of the file. - (useful if the file contain a self extractor code) - if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will - add files in existing zip (be sure you don't add file that doesn't exist) - If the zipfile cannot be opened, the return value is NULL. - Else, the return value is a zipFile Handle, usable with other function - of this zip package. -*/ - -/* Note : there is no delete function into a zipfile. - If you want delete file into a zipfile, you must open a zipfile, and create another - Of couse, you can use RAW reading and writing to copy the file you did not want delte -*/ - -extern zipFile ZEXPORT zipOpen2 OF((voidpf file, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level)); -/* - Open a file in the ZIP for writing. - filename : the filename in zip (if NULL, '-' without quote will be used - *zipfi contain supplemental information - if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header - if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header - if comment != NULL, comment contain the comment string - method contain the compression method (0 for store, Z_DEFLATED for deflate) - level contain the level of compression (can be Z_DEFAULT_COMPRESSION) -*/ - - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); - -/* - Same than zipOpenNewFileInZip, except if raw=1, we write raw file - */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCtypting)); - -/* - Same than zipOpenNewFileInZip2, except - windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCtypting : crc of file to compress (needed for crypting) - */ - - -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, - const void* buf, - unsigned len)); -/* - Write data in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); -/* - Close the current file in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, - uLong uncompressed_size, - uLong crc32)); -/* - Close the current file in the zipfile, for fiel opened with - parameter raw=1 in zipOpenNewFileInZip2 - uncompressed_size and crc32 are value for the uncompressed size -*/ - -extern int ZEXPORT zipClose OF((zipFile file, - const char* global_comment)); -/* - Close the zipfile -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _zip_H */ diff -r 39f8ea1a441f -r bcebfc477459 misc/quazip/zlib.h --- a/misc/quazip/zlib.h Sat Nov 17 20:27:49 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1368 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.3, July 18th, 2005 - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" -#include "qconfig.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.3" -#define ZLIB_VERNUM 0x1230 - -#if defined(QT_VISIBILITY_AVAILABLE) -# define Q_ZEXPORT __attribute__((visibility("default"))) -#else -# ifdef QT_MAKEDLL -# define Q_ZEXPORT __declspec(dllexport) -# else -# define Q_ZEXPORT ZEXPORT -# endif -#endif - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip streams in memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - /* basic functions */ - -ZEXTERN Q_ZEXPORT const char * zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -ZEXTERN int Q_ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumualte before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - the value returned by deflateBound (see below). If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. -*/ - - -ZEXTERN int Q_ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -ZEXTERN int Q_ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -ZEXTERN int Q_ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), - no header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as - Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy - parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. Z_FIXED prevents the - use of dynamic Huffman codes, allowing for a simpler decoder for special - applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int Q_ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. This function must be called - immediately after deflateInit, deflateInit2 or deflateReset, before any - call of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size in - deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. In addition, the - current implementation of deflate will use at most the window size minus - 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if the compression method is bsort). deflateSetDictionary does not - perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int Q_ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int Q_ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int Q_ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different - strategy. If the compression level is changed, the input available so far - is compressed with the old level (and may be flushed); the new level will - take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() - or deflateInit2(). This would be used to allocate an output buffer - for deflation in a single pass, and so would be called before deflate(). -*/ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the - bits leftover from a previous deflate stream when appending to it. As such, - this function can only be used for raw deflate, and must be used before the - first deflate() call after a deflateInit2() or deflateReset(). bits must be - less than or equal to 16, and that many of the least significant bits of - value will be inserted in the output. - - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -ZEXTERN int Q_ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called - immediately after inflateInit2() or inflateReset() and before any call of - inflate() to set the dictionary. The application must insure that the - dictionary that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int Q_ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int Q_ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK can be used to - force inflate() to return immediately after header processing is complete - and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When - any of extra, name, or comment are not Z_NULL and the respective field is - not present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the paramaters are invalid, Z_MEM_ERROR if the internal state could not - be allocated, or Z_VERSION_ERROR if the version of the library does not - match the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is more efficient than inflate() for - file i/o applications in that it avoids copying between the output and the - sliding window by simply making the window itself the output buffer. This - function trusts the application to not change the output buffer passed by - the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free - the allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects - only the raw deflate stream to decompress. This is different from the - normal behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format - error in the deflate stream (in which case strm->msg is set to indicate the - nature of the error), or Z_STREAM_ERROR if the stream was not properly - initialized. In the case of Z_BUF_ERROR, an input or output error can be - distinguished using strm->next_in which will be Z_NULL only if in() returned - an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to - out() returning non-zero. (in() will always be called before out(), so - strm->next_in is assured to be defined if out() returns non-zero.) Note - that inflateBack() cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - - - /* utility functions */ - -/* - The following utility functions are implemented on top of the - basic stream-oriented functions. To simplify the interface, some - default options are assumed (compression level and memory usage, - standard memory allocation functions). The source code of these - utility functions can easily be modified if you need special options. -*/ - -ZEXTERN int Q_ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be at least the value returned - by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - This function can be used to compress a whole file at once if the - input file is mmap'ed. - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int Q_ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before - a compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int Q_ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. - This function can be used to decompress a whole file at once if the - input file is mmap'ed. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -*/ - - -typedef voidp gzFile; - -ZEXTERN gzFile Q_ZEXPORT gzopen OF((const char *path, const char *mode)); -/* - Opens a gzip (.gz) file for reading or writing. The mode parameter - is as in fopen ("rb" or "wb") but can also include a compression level - ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for - Huffman only compression as in "wb1h", or 'R' for run-length encoding - as in "wb1R". (See the description of deflateInit2 for more information - about the strategy parameter.) - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. - - gzopen returns NULL if the file could not be opened or if there was - insufficient memory to allocate the (de)compression state; errno - can be checked to distinguish the two cases (if errno is zero, the - zlib error is Z_MEM_ERROR). */ - -ZEXTERN gzFile Q_ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen() associates a gzFile with the file descriptor fd. File - descriptors are obtained from calls like open, dup, creat, pipe or - fileno (in the file has been previously opened with fopen). - The mode parameter is as in gzopen. - The next call of gzclose on the returned gzFile will also close the - file descriptor fd, just like fclose(fdopen(fd), mode) closes the file - descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). - gzdopen returns NULL if there was insufficient memory to allocate - the (de)compression state. -*/ - -ZEXTERN int Q_ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. -*/ - -ZEXTERN int Q_ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. - If the input file was not in gzip format, gzread copies the given number - of bytes into the buffer. - gzread returns the number of uncompressed bytes actually read (0 for - end of file, -1 for error). */ - -ZEXTERN int Q_ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes actually written - (0 in case of error). -*/ - -ZEXTERN int Q_ZEXPORT gzprintf OF((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the args to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written (0 in case of error). The number of - uncompressed bytes written is limited to 4095. The caller should assure that - this limit is not exceeded. If it is exceeded, then gzprintf() will return - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. -*/ - -ZEXTERN int Q_ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN Q_ZEXPORT char * gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or - a newline character is read and transferred to buf, or an end-of-file - condition is encountered. The string is then terminated with a null - character. - gzgets returns buf, or Z_NULL in case of error. -*/ - -ZEXTERN int Q_ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. - gzputc returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int Q_ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte - or -1 in case of end of file or error. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read again later. - Only one character of push-back is allowed. gzungetc() returns the - character pushed, or -1 on failure. gzungetc() will fail if a - character has been pushed but not read yet, or if c is -1. The pushed - character will be discarded if the stream is repositioned with gzseek() - or gzrewind(). -*/ - -ZEXTERN int Q_ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter - flush is as in the deflate() function. The return value is the zlib - error number (see function gzerror below). gzflush returns Z_OK if - the flush parameter is Z_FINISH and all output could be flushed. - gzflush should be called only when strictly necessary because it can - degrade compression. -*/ - -ZEXTERN z_off_t Q_ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); -/* - Sets the starting position for the next gzread or gzwrite on the - given compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int Q_ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -ZEXTERN z_off_t Q_ZEXPORT gztell OF((gzFile file)); -/* - Returns the starting position for the next gzread or gzwrite on the - given compressed file. This position represents a number of bytes in the - uncompressed data stream. - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -ZEXTERN int Q_ZEXPORT gzeof OF((gzFile file)); -/* - Returns 1 when EOF has previously been detected reading the given - input stream, otherwise zero. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns 1 if file is being read directly without decompression, otherwise - zero. -*/ - -ZEXTERN int Q_ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file - and deallocates all the (de)compression state. The return value is the zlib - error number (see function gzerror below). -*/ - -ZEXTERN Q_ZEXPORT const char * gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the - given compressed file. errnum is set to zlib error number. If an - error occurred in the file system and not in the compression library, - errnum is set to Z_ERRNO and the application may consult errno - to get the exact error code. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the - compression library. -*/ - -ZEXTERN uLong Q_ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); -/* - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -*/ - -ZEXTERN uLong Q_ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is NULL, this function returns the required initial - value for the for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - -/* - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int Q_ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int Q_ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int Q_ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int Q_ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, sizeof(z_stream)) - - -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -ZEXTERN Q_ZEXPORT const char * zError OF((int)); -ZEXTERN int Q_ZEXPORT inflateSyncPoint OF((z_streamp z)); -ZEXTERN Q_ZEXPORT const uLongf * get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ diff -r 39f8ea1a441f -r bcebfc477459 project_files/hedgewars.pro --- a/project_files/hedgewars.pro Sat Nov 17 20:27:49 2012 -0500 +++ b/project_files/hedgewars.pro Sat Nov 17 20:30:32 2012 -0500 @@ -1,7 +1,7 @@ TEMPLATE = app TARGET = hedgewars DEPENDPATH += ../QTfrontend/ -INCLUDEPATH += ../QTfrontend/ +INCLUDEPATH += ../QTfrontend INCLUDEPATH += ../QTfrontend/model INCLUDEPATH += ../QTfrontend/ui INCLUDEPATH += ../QTfrontend/ui/widget @@ -9,7 +9,8 @@ INCLUDEPATH += ../QTfrontend/ui/dialog INCLUDEPATH += ../QTfrontend/net INCLUDEPATH += ../QTfrontend/util -INCLUDEPATH += ../misc/quazip/ +INCLUDEPATH += ../misc/physfs/src +INCLUDEPATH += ../misc/physfs/extras DESTDIR = ../bin @@ -105,7 +106,8 @@ ../QTfrontend/ui/dialog/upload_video.h \ ../QTfrontend/campaign.h \ ../QTfrontend/model/playerslistmodel.h \ - ../QTfrontend/util/LibavInteraction.h + ../QTfrontend/util/LibavInteraction.h \ + ../QTfrontend/util/FileEngine.h SOURCES += ../QTfrontend/model/ammoSchemeModel.cpp \ @@ -195,7 +197,8 @@ ../QTfrontend/ui/dialog/upload_video.cpp \ ../QTfrontend/campaign.cpp \ ../QTfrontend/model/playerslistmodel.cpp \ - ../QTfrontend/util/LibavInteraction.cpp + ../QTfrontend/util/LibavInteraction.cpp \ + ../QTfrontend/util/FileEngine.cpp TRANSLATIONS += ../share/hedgewars/Data/Locale/hedgewars_ar.ts \ @@ -230,7 +233,7 @@ RESOURCES += ../QTfrontend/hedgewars.qrc -LIBS += -L../bin -lquazip +LIBS += -L../bin -lphysfs -lphysfsrwops macx { QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Constants--------------------------------- choiceAccepted = 1 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Map-------------------------------------- local map = diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") --------------------------------------------Constants------------------------------------ diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Constants--------------------------------- leaksNum = 1 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Map-------------------------------------- local map = diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Variables--------------------------------- startDialogue = {} diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") --///////////////////////////////CONSTANTS/////////////////////////// diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Map-------------------------------------- diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Constants--------------------------------- startStage = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua --- a/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Animate.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Animate.lua") -----------------------------Constants--------------------------------- choiceAccept = 1 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Bazooka.lua Sat Nov 17 20:30:32 2012 -0500 @@ -13,7 +13,7 @@ -- about translations. -- We can use the function loc(text) to localize a string. -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") -- This variable will hold the number of destroyed targets. local score = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Cluster_Bomb.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,4 +1,4 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil local scored = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Grenade.lua Sat Nov 17 20:30:32 2012 -0500 @@ -13,7 +13,7 @@ -- about translations. -- We can use the function loc(text) to localize a string. -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") -- This variable will hold the number of destroyed targets. local score = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Rope.lua Sat Nov 17 20:30:32 2012 -0500 @@ -7,8 +7,8 @@ --I know there need to be more "tutorial" specefic messages, but I had a hard timer figuring out what to type / what would be the best technical description. -loadfile( GetDataPath() .. "Scripts/Locale.lua" )() -loadfile( GetDataPath() .. "Scripts/Utils.lua" )() -- For the gearIsInBox function, wrote my own, but decided it was a waste to include it +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Utils.lua") -- For the gearIsInBox function, wrote my own, but decided it was a waste to include it local Player = nil -- Pointer to hog created in: onGameInit local Target = nil -- Pointer to target hog diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Shotgun.lua Sat Nov 17 20:30:32 2012 -0500 @@ -13,7 +13,7 @@ -- about translations. -- We can use the function loc(text) to localize a string. -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") -- This variable will hold the number of destroyed targets. local score = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua --- a/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/Basic_Training_-_Sniper_Rifle.lua Sat Nov 17 20:30:32 2012 -0500 @@ -13,7 +13,7 @@ -- about translations. -- We can use the function loc(text) to localize a string. -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") -- This variable will hold the number of destroyed targets. local score = 0 diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Bamboo_Thicket.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil local enemy = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Dangerous_Ducklings.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil -- This variable will point to the hog's gear diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Diver.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil -- This variable will point to the hog's gear local enemy = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Newton_and_the_Hammock.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil local enemy = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_RCPlane_Challenge.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,4 +1,4 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil local RCGear = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Rope_Knock_Challenge.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,4 +1,4 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local hhs = {} local missionWon = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Spooky_Tree.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") --------------------------------------------------------------- diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_Teamwork.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,4 +1,4 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil -- This variable will point to the hog's gear local p2 = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_That_Sinking_Feeling.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,6 +1,6 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player local hh = {} diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua --- a/share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/User_Mission_-_The_Great_Escape.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,4 +1,4 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local player = nil local enemy = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Missions/Training/portal.lua --- a/share/hedgewars/Data/Missions/Training/portal.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Missions/Training/portal.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Utils.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Utils.lua") local MineArray = {} local player diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,5 +1,5 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amMine, amDEagle, amDynamite, amFirePunch, amWhip, amPickHammer, amBaseballBat, amMortar, amCake, amSeduction, amWatermelon, amHellishBomb, amDrill, amBallgun, amRCPlane, amSniperRifle, amMolotov, amBirdy, amBlowTorch, amGasBomb, amFlamethrower, amSMine, amKamikaze } diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.lua Sat Nov 17 20:30:32 2012 -0500 @@ -75,7 +75,7 @@ ----------------- -- enable awesome translaction support so we can use loc() wherever we want -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") --------------------------------------------------------------- ----------lots of bad variables and things diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Continental_supplies.lua Sat Nov 17 20:30:32 2012 -0500 @@ -10,9 +10,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Utils.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Utils.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") function int_sqrt(num) temp=num diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Sat Nov 17 20:30:32 2012 -0500 @@ -51,8 +51,8 @@ -- added napalm (whoops) to list of possible weapons you can get -- hogs no longer recieve airstrike-related weps on border maps -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") local airWeapons = {amAirAttack, amMineStrike, amNapalm, amDrillStrike --[[,amPiano]]} diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua Sat Nov 17 20:30:32 2012 -0500 @@ -52,8 +52,8 @@ --]] -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") --[[ MUTANT SCRIPT diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.lua Sat Nov 17 20:30:32 2012 -0500 @@ -2,7 +2,7 @@ -- NO JUMPING -------------------------------- -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") local specialGear = nil diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Racer.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua Sat Nov 17 20:30:32 2012 -0500 @@ -65,7 +65,7 @@ -- SCRIPT BEGINS ----------------------------- -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") ------------------ -- Got Variables? diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,10 +1,10 @@ -- Random Weapons, example for gameplay scripts -- Load the library for localisation ("loc" function) -loadfile(GetDataPath() .. "Scripts/Locale.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") -- Load the gear tracker -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Tracker.lua") -- List of available weapons local weapons = { amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.lua Sat Nov 17 20:30:32 2012 -0500 @@ -1,6 +1,6 @@ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") --------------------------------------------------- --------------------------------------------------- diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.lua Sat Nov 17 20:30:32 2012 -0500 @@ -52,8 +52,8 @@ -- balance hog health, maybe -- add proper gameflag checking, maybe (so that we can throw in a .cfg and let the users break everything) -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") local numhhs = 0 local hhs = {} diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.lua Sat Nov 17 20:30:32 2012 -0500 @@ -3,8 +3,8 @@ -- v.0.7.1 ------------------------------------ -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") local fMod = 1000000 -- use this for dev and .16+ games diff -r 39f8ea1a441f -r bcebfc477459 share/hedgewars/Data/Scripts/Multiplayer/WxW.lua --- a/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua Sat Nov 17 20:27:49 2012 -0500 +++ b/share/hedgewars/Data/Scripts/Multiplayer/WxW.lua Sat Nov 17 20:30:32 2012 -0500 @@ -54,9 +54,9 @@ -- GO PONIES, GO PONIES, GO! ----------------------------- -loadfile(GetDataPath() .. "Scripts/Locale.lua")() -loadfile(GetDataPath() .. "Scripts/Tracker.lua")() -loadfile(GetDataPath() .. "Scripts/Utils.lua")() +HedgewarsScriptLoad("/Scripts/Locale.lua") +HedgewarsScriptLoad("/Scripts/Tracker.lua") +HedgewarsScriptLoad("/Scripts/Utils.lua") -- experimental menu stuff local menuIndex = 1