mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Replace BSAOpt hash calculation with a custom function
This commit is contained in:
parent
c2fd4c1f46
commit
c9df63ffd1
6 changed files with 36 additions and 187 deletions
|
@ -610,7 +610,6 @@ add_subdirectory (extern/oics)
|
|||
if (BUILD_OPENCS)
|
||||
add_subdirectory (extern/osgQt)
|
||||
endif()
|
||||
add_subdirectory (extern/BSAOpt)
|
||||
|
||||
# Components
|
||||
add_subdirectory (components)
|
||||
|
|
|
@ -28,12 +28,9 @@
|
|||
#include <cassert>
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <extern/BSAOpt/hash.hpp> // see: http://en.uesp.net/wiki/Tes4Mod:Hash_Calculation
|
||||
|
||||
#include <boost/iostreams/filtering_streambuf.hpp>
|
||||
#include <boost/iostreams/copy.hpp>
|
||||
#include <boost/iostreams/filter/zlib.hpp>
|
||||
|
@ -197,8 +194,7 @@ void CompressedBSAFile::readHeader()
|
|||
if ((archiveFlags & 0x1) != 0)
|
||||
getBZString(folder, input);
|
||||
|
||||
std::string emptyString;
|
||||
folderHash = GenOBHash(folder, emptyString);
|
||||
folderHash = generateHash(folder, std::string());
|
||||
|
||||
std::map<std::uint64_t, FolderRecord>::iterator iter = mFolders.find(folderHash);
|
||||
if (iter == mFolders.end())
|
||||
|
@ -297,20 +293,13 @@ CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string
|
|||
p.remove_filename();
|
||||
|
||||
std::string folder = p.string();
|
||||
// GenOBHash already converts to lowercase and replaces file separators but not for path
|
||||
boost::algorithm::to_lower(folder);
|
||||
std::replace(folder.begin(), folder.end(), '/', '\\');
|
||||
|
||||
std::string emptyString;
|
||||
std::uint64_t folderHash = GenOBHash(folder, emptyString);
|
||||
std::uint64_t folderHash = generateHash(folder, std::string());
|
||||
|
||||
std::map<std::uint64_t, FolderRecord>::const_iterator it = mFolders.find(folderHash);
|
||||
if (it == mFolders.end())
|
||||
return FileRecord(); // folder not found, return default which has offset of sInvalidOffset
|
||||
|
||||
boost::algorithm::to_lower(stem);
|
||||
boost::algorithm::to_lower(ext);
|
||||
std::uint64_t fileHash = GenOBHashPair(stem, ext);
|
||||
std::uint64_t fileHash = generateHash(stem, ext);
|
||||
std::map<std::uint64_t, FileRecord>::const_iterator iter = it->second.files.find(fileHash);
|
||||
if (iter == it->second.files.end())
|
||||
return FileRecord(); // file not found, return default which has offset of sInvalidOffset
|
||||
|
@ -430,4 +419,35 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed()
|
|||
}
|
||||
}
|
||||
|
||||
std::uint64_t CompressedBSAFile::generateHash(std::string stem, std::string extension) const
|
||||
{
|
||||
size_t len = stem.length();
|
||||
if (len == 0) return 0;
|
||||
std::uint64_t hash = 0;
|
||||
unsigned int hash2 = 0;
|
||||
Misc::StringUtils::lowerCaseInPlace(stem);
|
||||
if (extension.empty()) // It's a folder.
|
||||
std::replace(stem.begin(), stem.end(), '/', '\\');
|
||||
else
|
||||
{
|
||||
Misc::StringUtils::lowerCaseInPlace(extension);
|
||||
for (const char &c : extension)
|
||||
hash = hash * 0x1003f + c;
|
||||
}
|
||||
for (size_t i = 1; i < len-2 && len > 3; i++)
|
||||
hash2 = hash2 * 0x1003f + stem[i];
|
||||
hash = (hash + hash2) << 32;
|
||||
hash2 = (stem[0] << 24) | (len << 16);
|
||||
if (len >= 3) hash2 |= stem[len-2] << 8;
|
||||
if (len >= 2) hash2 |= stem[len-1];
|
||||
if (!extension.empty())
|
||||
{
|
||||
if (extension == ".kf") hash2 |= 0x80;
|
||||
else if (extension == ".nif") hash2 |= 0x8000;
|
||||
else if (extension == ".dds") hash2 |= 0x8080;
|
||||
else if (extension == ".wav") hash2 |= 0x80000000;
|
||||
}
|
||||
return hash + hash2;
|
||||
}
|
||||
|
||||
} //namespace Bsa
|
||||
|
|
|
@ -26,10 +26,6 @@
|
|||
#ifndef BSA_COMPRESSED_BSA_FILE_H
|
||||
#define BSA_COMPRESSED_BSA_FILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <components/bsa/bsa_file.hpp>
|
||||
|
||||
namespace Bsa
|
||||
|
@ -81,6 +77,8 @@ namespace Bsa
|
|||
void getBZString(std::string& str, std::istream& filestream);
|
||||
//mFiles used by OpenMW will contain uncompressed file sizes
|
||||
void convertCompressedSizesToUncompressed();
|
||||
/// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation.
|
||||
std::uint64_t generateHash(std::string stem, std::string extension) const;
|
||||
Files::IStreamPtr getFile(const FileRecord& fileRecord);
|
||||
public:
|
||||
CompressedBSAFile();
|
||||
|
|
17
extern/BSAOpt/CMakeLists.txt
vendored
17
extern/BSAOpt/CMakeLists.txt
vendored
|
@ -1,17 +0,0 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project.
|
||||
|
||||
set(BSAOPTHASH_LIBRARY "bsaopthash")
|
||||
|
||||
# Sources
|
||||
set(SOURCE_FILES
|
||||
hash.cpp
|
||||
)
|
||||
|
||||
add_library(${BSAOPTHASH_LIBRARY} STATIC ${SOURCE_FILES})
|
||||
|
||||
set(BSAOPTHASH_LIBRARIES ${BSAOPTHASH_LIBRARY})
|
||||
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(BSAOPTHASH_LIBRARIES ${BSAOPTHASH_LIBRARIES} PARENT_SCOPE)
|
109
extern/BSAOpt/hash.cpp
vendored
109
extern/BSAOpt/hash.cpp
vendored
|
@ -1,109 +0,0 @@
|
|||
/* Version: MPL 1.1/LGPL 3.0
|
||||
*
|
||||
* "The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is BSAopt.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ethatron <niels@paradice-insight.us>. Portions created by The Initial
|
||||
* Developer are Copyright (C) 2011 The Initial Developer.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU Library General Public License Version 3 license (the
|
||||
* "LGPL License"), in which case the provisions of LGPL License are
|
||||
* applicable instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the LGPL License and not
|
||||
* to allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and replace
|
||||
* them with the notice and other provisions required by the LGPL License.
|
||||
* If you do not delete the provisions above, a recipient may use your
|
||||
* version of this file under either the MPL or the LGPL License."
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "hash.hpp"
|
||||
|
||||
std::uint32_t GenOBHashStr(const std::string& s) {
|
||||
std::uint32_t hash = 0;
|
||||
|
||||
for (std::size_t i = 0; i < s.length(); i++) {
|
||||
hash *= 0x1003F;
|
||||
hash += (unsigned char)s[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::uint64_t GenOBHashPair(const std::string& fle, const std::string& ext) {
|
||||
std::uint64_t hash = 0;
|
||||
|
||||
if (fle.length() > 0) {
|
||||
hash = (std::uint64_t)(
|
||||
(((unsigned char)fle[fle.length() - 1]) * 0x1) +
|
||||
((fle.length() > 2 ? (unsigned char)fle[fle.length() - 2] : (unsigned char)0) * 0x100) +
|
||||
(fle.length() * 0x10000) +
|
||||
(((unsigned char)fle[0]) * 0x1000000)
|
||||
);
|
||||
|
||||
if (fle.length() > 3) {
|
||||
hash += (std::uint64_t)(GenOBHashStr(fle.substr(1, fle.length() - 3)) * 0x100000000);
|
||||
}
|
||||
}
|
||||
|
||||
if (ext.length() > 0) {
|
||||
hash += (std::uint64_t)(GenOBHashStr(ext) * 0x100000000LL);
|
||||
|
||||
unsigned char i = 0;
|
||||
if (ext == ".nif") i = 1;
|
||||
if (ext == ".kf" ) i = 2;
|
||||
if (ext == ".dds") i = 3;
|
||||
if (ext == ".wav") i = 4;
|
||||
|
||||
if (i != 0) {
|
||||
unsigned char a = (unsigned char)(((i & 0xfc ) << 5) + (unsigned char)((hash & 0xff000000) >> 24));
|
||||
unsigned char b = (unsigned char)(((i & 0xfe ) << 6) + (unsigned char)( hash & 0x000000ff) );
|
||||
unsigned char c = (unsigned char)(( i << 7) + (unsigned char)((hash & 0x0000ff00) >> 8));
|
||||
|
||||
hash -= hash & 0xFF00FFFF;
|
||||
hash += (std::uint32_t)((a << 24) + b + (c << 8));
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::uint64_t GenOBHash(const std::string& path, std::string& file) {
|
||||
std::transform(file.begin(), file.end(), file.begin(), ::tolower);
|
||||
std::replace(file.begin(), file.end(), '/', '\\');
|
||||
|
||||
std::string fle;
|
||||
std::string ext;
|
||||
|
||||
const char *_fle = file.data();
|
||||
const char *_ext = strrchr(_fle, '.');
|
||||
if (_ext) {
|
||||
ext = file.substr((0 + _ext) - _fle);
|
||||
fle = file.substr(0, ( _ext) - _fle);
|
||||
}
|
||||
else {
|
||||
ext = "";
|
||||
fle = file;
|
||||
}
|
||||
|
||||
if (path.length() && fle.length())
|
||||
return GenOBHashPair(path + "\\" + fle, ext);
|
||||
else
|
||||
return GenOBHashPair(path + fle, ext);
|
||||
}
|
42
extern/BSAOpt/hash.hpp
vendored
42
extern/BSAOpt/hash.hpp
vendored
|
@ -1,42 +0,0 @@
|
|||
/* Version: MPL 1.1/LGPL 3.0
|
||||
*
|
||||
* "The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is BSAopt.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ethatron <niels@paradice-insight.us>. Portions created by The Initial
|
||||
* Developer are Copyright (C) 2011 The Initial Developer.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms
|
||||
* of the GNU Library General Public License Version 3 license (the
|
||||
* "LGPL License"), in which case the provisions of LGPL License are
|
||||
* applicable instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the LGPL License and not
|
||||
* to allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and replace
|
||||
* them with the notice and other provisions required by the LGPL License.
|
||||
* If you do not delete the provisions above, a recipient may use your
|
||||
* version of this file under either the MPL or the LGPL License."
|
||||
*/
|
||||
#ifndef BSAOPT_HASH_H
|
||||
#define BSAOPT_HASH_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::uint32_t GenOBHashStr(const std::string& s);
|
||||
|
||||
std::uint64_t GenOBHashPair(const std::string& fle, const std::string& ext);
|
||||
|
||||
std::uint64_t GenOBHash(const std::string& path, std::string& file);
|
||||
|
||||
#endif // BSAOPT_HASH_H
|
Loading…
Reference in a new issue