/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * resource.cc * * Sun Mar 17 19:38:04 CET 2013 * Copyright 2013 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of DrumGizmo. * * DrumGizmo 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 3 of the License, or * (at your option) any later version. * * DrumGizmo 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 DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "resource.h" #include #include #include #include #if DG_PLATFORM != DG_PLATFORM_WINDOWS #include #include #include #endif // rcgen generated file containing rc_data declaration. #include "resource_data.h" extern const rc_data_t* rc_data; namespace dggui { // TODO: Replace with std::filesystem::is_regular_file once we update the // compiler to require C++17 static bool pathIsFile(const std::string& path) { #if DG_PLATFORM == DG_PLATFORM_WINDOWS return (GetFileAttributesA(path.data()) & FILE_ATTRIBUTE_DIRECTORY) == 0; #else struct stat s; if(stat(path.data(), &s) != 0) { return false; // error } return (s.st_mode & S_IFREG) != 0; // s.st_mode & S_IFDIR => dir #endif } // Internal resources start with a colon. static bool nameIsInternal(const std::string& name) { return name.size() && (name[0] == ':'); } Resource::Resource(const std::string& name) { isValid = false; if(nameIsInternal(name)) { // Use internal resource: // Find internal resource in rc_data. const rc_data_t* p = rc_data; while(p && *p->name) // last entry in rc_data has the name := "" { if(name == p->name) { internalData = p->data; internalSize = p->size; break; } ++p; } // We did not find the named resource. if(internalData == nullptr) { ERR(rc, "Could not find '%s'\n", name.c_str()); return; } isInternal = true; } else { if(!pathIsFile(name)) { return; } // Read from file: std::FILE *fp = std::fopen(name.data(), "rb"); if(!fp) { return; } // Get the file size if(std::fseek(fp, 0, SEEK_END) == -1) { std::fclose(fp); return; } long filesize = std::ftell(fp); // Apparently fseek doesn't fail if fp points to a directory that has been // opened (which doesn't fail either!!) and ftell will then fail by either // returning -1 or LONG_MAX if(filesize == -1L || filesize == LONG_MAX) { std::fclose(fp); return; } // Reserve space in the string for the data. externalData.reserve(filesize); // Rewind and read... std::rewind(fp); char buffer[32]; while(!std::feof(fp)) { size_t size = std::fread(buffer, 1, sizeof(buffer), fp); externalData.append(buffer, size); } std::fclose(fp); isInternal = false; } isValid = true; } const char *Resource::data() { if(isValid == false) { return nullptr; } if(isInternal) { return internalData; } else { return externalData.data(); } } size_t Resource::size() { if(isValid == false) { return 0; } if(isInternal) { return internalSize; } else { return externalData.length(); } } bool Resource::valid() { return isValid; } } // dggui::