Skip to content
Snippets Groups Projects
fchost_storage.cc 3.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "fchost_storage.h"
    
    #include <algorithm>
    
    ezsh's avatar
    ezsh committed
    #include <cstdio>
    #include <memory>
    #include <vector>
    
    namespace fs = std::filesystem;
    
    namespace {
    	struct closeFile {
    		void operator()(std::FILE* f) const noexcept
    		{
    			std::fclose(f);
    		}
    	};
    }
    
    
    CefRefPtr<CefV8Value> FCHostSessionStorage::keys() const
    {
    
    klorpa's avatar
    klorpa committed
    	// holy hell this is awful. I hope Sugarcube doesn't actually USE this...
    
    	CefRefPtr<CefV8Value> ret = CefV8Value::CreateArray(static_cast<int>(storage.size()));
    	auto itr = storage.cbegin();
    	for (int i = 0; i < static_cast<int>(storage.size()); ++i, ++itr)
    	{
    		ret->SetValue(i, CefV8Value::CreateString(itr->first));
    	}
    	return ret;
    }
    
    
    klorpa's avatar
    klorpa committed
    /* This shouldn't happen, so don't waste time on it. Sugarcube really only writes simple alphanumeric keys.
    
    static bool SanitizePath(std::wstring& inpath)
    {
    	std::transform(inpath.begin(), inpath.end(), inpath.begin(), [](wchar_t c)
    	{
    		if (PathGetCharTypeW(c) != GCT_LFNCHAR)
    			return L'_';
    		else
    			return c;
    	});
    }
    */
    
    
    ezsh's avatar
    ezsh committed
    FCHostPersistentStorage::FCHostPersistentStorage(const CefString& _path)
    #if defined(OS_WIN)
    	: path(_path.ToWString())
    #else
    	: path(_path.ToString())
    #endif
    {
    	ensure_folder_exists();
    	load();
    }
    
    
    void FCHostPersistentStorage::set(const CefString& key, CefRefPtr<CefV8Value> val)
    {
    
    ezsh's avatar
    ezsh committed
    	base::set(key, val);
    
    klorpa's avatar
    klorpa committed
    	// only strings get persisted (should be OK, Sugarcube will serialize first)
    
    	if (val->IsString())
    	{
    		// we should probably be doing this async but TBT Sugarcube is the slow part, not the file IO
    
    ezsh's avatar
    ezsh committed
    		std::unique_ptr<std::FILE, closeFile> fh;
    #if defined(OS_WIN)
    		fh.reset(_wfopen(get_filename(key).c_str(), L"w"));
    #else
    		fh.reset(std::fopen(get_filename(key).c_str(), "w"));
    #endif
    
    		CefString valStr = val->GetStringValue();
    
    ezsh's avatar
    ezsh committed
    		if (valStr.size() > 0) {
    			std::fwrite(valStr.c_str(), static_cast<size_t>(valStr.size() * sizeof(valStr.c_str()[0])), 1, fh.get());
    
    		}
    	}
    }
    
    bool FCHostPersistentStorage::remove(const CefString& key)
    {
    
    ezsh's avatar
    ezsh committed
    	fs::remove(get_filename(key));
    	return base::remove(key);
    
    ezsh's avatar
    ezsh committed
    	for (const auto& entry: fs::directory_iterator(path)) {
    		if (fs::is_regular_file(entry.path())) {
    			fs::remove_all(entry.path());
    		}
    
    ezsh's avatar
    ezsh committed
    	base::clear();
    
    ezsh's avatar
    ezsh committed
    	std::vector<char> readbuf;
    
    	std::unique_ptr<std::FILE, closeFile> fh;
    	for (const auto& entry: fs::directory_iterator(path)) {
    		if (fs::is_regular_file(entry.path())) {
    			const auto entrySize = fs::file_size(entry.path());
    			readbuf.resize(static_cast<std::size_t>(entrySize + 2)); // +1 wchar_t
    
    #if defined(OS_WIN)
    			fh.reset(_wfopen(entry.path().c_str(), L"r"));
    #else
    			fh.reset(std::fopen(entry.path().c_str(), "r"));
    #endif
    			if (std::fread(&readbuf[0], entrySize, 1, fh.get())) {
    				readbuf[entrySize + 1] = readbuf[entrySize] = 0; // null terminate
    				CefString val = static_cast<const wchar_t*>(static_cast<const void*>(readbuf.data()));
    				storage.emplace(entry.path().filename().native(), CefV8Value::CreateString(val));
    
    ezsh's avatar
    ezsh committed
    fs::path FCHostPersistentStorage::get_filename(const CefString& key) const
    
    ezsh's avatar
    ezsh committed
    #if defined (OS_WIN)
    	return path / key.ToWString();
    #else
    	return path / key.ToString();
    #endif
    
    }
    
    void FCHostPersistentStorage::ensure_folder_exists() const
    {
    	// ignore returned errors
    
    ezsh's avatar
    ezsh committed
    	fs::create_directories(path);