🎨 Convert to a header-only library (#6)
This commit is contained in:
parent
f7fe31739e
commit
c7b0151510
24
.clang-format
Normal file
24
.clang-format
Normal file
@ -0,0 +1,24 @@
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
BasedOnStyle: Microsoft
|
||||
BreakBeforeBraces: Allman
|
||||
ColumnLimit: 130
|
||||
Cpp11BracedListStyle: true
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Regroup
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentWidth: 4
|
||||
Language: Cpp
|
||||
NamespaceIndentation: All
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInParentheses: false
|
||||
Standard: c++11
|
||||
UseTab: Never
|
21
.github/workflows/main.yml
vendored
Normal file
21
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Build & Test
|
||||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
build:
|
||||
name: Testing on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Configure
|
||||
run: cmake -DBUILD_TEST=ON .
|
||||
|
||||
- name: Build
|
||||
run: cmake --build .
|
||||
|
||||
- name: Test
|
||||
run: ctest -C Debug .
|
40
.travis.yml
40
.travis.yml
@ -1,40 +0,0 @@
|
||||
|
||||
env:
|
||||
global:
|
||||
- CONAN_REFERENCE: "MofileReader/1.0.0"
|
||||
- CONAN_USERNAME: "anotherfoxguy"
|
||||
- CONAN_LOGIN_USERNAME: "anotherfoxguy"
|
||||
- CONAN_CHANNEL: "testing"
|
||||
- CONAN_UPLOAD: "https://api.bintray.com/conan/anotherfoxguy/ror-dependencies"
|
||||
|
||||
linux: &linux
|
||||
os: linux
|
||||
sudo: required
|
||||
language: python
|
||||
python: "3.6"
|
||||
services:
|
||||
- docker
|
||||
osx: &osx
|
||||
os: osx
|
||||
language: generic
|
||||
matrix:
|
||||
include:
|
||||
- <<: *linux
|
||||
env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=conanio/gcc5
|
||||
|
||||
- <<: *linux
|
||||
env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=conanio/gcc6
|
||||
|
||||
- <<: *linux
|
||||
env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=conanio/gcc7
|
||||
|
||||
- <<: *linux
|
||||
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8
|
||||
|
||||
install:
|
||||
- chmod +x .travis/install.sh
|
||||
- ./.travis/install.sh
|
||||
|
||||
script:
|
||||
- chmod +x .travis/run.sh
|
||||
- ./.travis/run.sh
|
@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [[ "$(uname -s)" == 'Darwin' ]]; then
|
||||
brew update || brew update
|
||||
brew outdated pyenv || brew upgrade pyenv
|
||||
brew install pyenv-virtualenv
|
||||
brew install cmake || true
|
||||
|
||||
if which pyenv > /dev/null; then
|
||||
eval "$(pyenv init -)"
|
||||
fi
|
||||
|
||||
pyenv install 2.7.10
|
||||
pyenv virtualenv 2.7.10 conan
|
||||
pyenv rehash
|
||||
pyenv activate conan
|
||||
fi
|
||||
|
||||
pip install conan --upgrade
|
||||
pip install conan_package_tools
|
||||
|
||||
conan user
|
@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [[ "$(uname -s)" == 'Darwin' ]]; then
|
||||
if which pyenv > /dev/null; then
|
||||
eval "$(pyenv init -)"
|
||||
fi
|
||||
pyenv activate conan
|
||||
fi
|
||||
|
||||
python build.py
|
@ -1,55 +1,21 @@
|
||||
#-------------------------------------------------------
|
||||
# moFileReader Main Build Script
|
||||
#
|
||||
# Defined Variables:
|
||||
# - COMPILE_DLL
|
||||
# - ON : Compiles the code as a shared Library
|
||||
# - OFF : Compiles the code as a static Library
|
||||
# - BUILD_DEBUG
|
||||
# - ON : Compiles Debug-Information into the output
|
||||
# - OFF : Optimizes the compilation with O2.
|
||||
#
|
||||
# Run cmake with -DVARNAME=ON/OFF to benefit from those
|
||||
# possible settings.
|
||||
#-------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
project(moFileReader)
|
||||
|
||||
# Let the user choose between static lib and dll
|
||||
# To use it, call cmake -DCOMPILE_DLL=ON
|
||||
option(COMPILE_DLL "Set this to ON if you want to compile the library as an DLL. When this is OFF, a static library is created (default)." OFF)
|
||||
if (COMPILE_DLL)
|
||||
# DLL
|
||||
target_compile_definitions(moReader PRIVATE _USRDLL MOFILE_EXPORTS)
|
||||
endif ()
|
||||
|
||||
add_library(moFileReader STATIC ${CMAKE_SOURCE_DIR}/src/moFileReader.cpp ${CMAKE_SOURCE_DIR}/src/mo.cpp)
|
||||
add_executable(moReader ${CMAKE_SOURCE_DIR}/src/mo.cpp)
|
||||
|
||||
target_include_directories(moFileReader PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_include_directories(moReader PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
if (COMPILE_DLL)
|
||||
target_compile_definitions(moReader PRIVATE _CONSOLE MOFILE_IMPORT)
|
||||
else ()
|
||||
target_compile_definitions(moReader PRIVATE _CONSOLE)
|
||||
endif ()
|
||||
|
||||
add_dependencies(moReader moFileReader)
|
||||
target_link_libraries(moReader moFileReader)
|
||||
|
||||
install(TARGETS moReader
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
install(TARGETS moFileReader
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
PUBLIC_HEADER DESTINATION include
|
||||
)
|
||||
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/)
|
||||
|
||||
option(BUILD_TEST "Set this to ON if you want to build the test" OFF)
|
||||
|
30
appveyor.yml
30
appveyor.yml
@ -1,30 +0,0 @@
|
||||
build: false
|
||||
|
||||
environment:
|
||||
PYTHON: "C:\\Python37"
|
||||
|
||||
CONAN_REFERENCE: "MofileReader/1.0.0"
|
||||
CONAN_USERNAME: "anotherfoxguy"
|
||||
CONAN_LOGIN_USERNAME: "anotherfoxguy"
|
||||
CONAN_CHANNEL: "testing"
|
||||
CONAN_UPLOAD: "https://api.bintray.com/conan/anotherfoxguy/ror-dependencies"
|
||||
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CONAN_VISUAL_VERSIONS: 16
|
||||
CONAN_BUILD_TYPES: Release
|
||||
CONAN_ARCHS: x86_64
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
CONAN_VISUAL_VERSIONS: 16
|
||||
CONAN_BUILD_TYPES: Debug
|
||||
CONAN_ARCHS: x86_64
|
||||
|
||||
|
||||
install:
|
||||
- set PATH=%PATH%;%PYTHON%/Scripts/
|
||||
- pip.exe install conan --upgrade
|
||||
- pip.exe install conan_package_tools
|
||||
- conan user # It creates the conan data directory
|
||||
|
||||
test_script:
|
||||
- python build.py
|
7
build.py
7
build.py
@ -1,7 +0,0 @@
|
||||
from conan.packager import ConanMultiPackager
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
builder = ConanMultiPackager()
|
||||
builder.add_common_builds()
|
||||
builder.run()
|
17
cmake/FindCatch2.cmake
Normal file
17
cmake/FindCatch2.cmake
Normal file
@ -0,0 +1,17 @@
|
||||
set(Catch2_FOUND TRUE)
|
||||
|
||||
set(CATCH2_VERSION "v2.13.4")
|
||||
set(CATCH2_INCLUDEDIR "${CMAKE_BINARY_DIR}/catch-${CATCH2_VERSION}")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CATCH2_INCLUDEDIR}")
|
||||
|
||||
if (NOT EXISTS "${CATCH2_INCLUDEDIR}/catch.hpp")
|
||||
file(MAKE_DIRECTORY "${CATCH2_INCLUDEDIR}")
|
||||
message(STATUS "Downloading catch.hpp from https://github.com/catchorg/Catch2/")
|
||||
file(DOWNLOAD "https://github.com/catchorg/Catch2/releases/download/${CATCH2_VERSION}/catch.hpp" "${CATCH2_INCLUDEDIR}/catch.hpp")
|
||||
file(DOWNLOAD "https://cdn.statically.io/gh/catchorg/Catch2/${CATCH2_VERSION}/contrib/Catch.cmake" "${CATCH2_INCLUDEDIR}/Catch.cmake")
|
||||
file(DOWNLOAD "https://cdn.statically.io/gh/catchorg/Catch2/${CATCH2_VERSION}/contrib/CatchAddTests.cmake" "${CATCH2_INCLUDEDIR}/CatchAddTests.cmake")
|
||||
file(DOWNLOAD "https://cdn.statically.io/gh/catchorg/Catch2/${CATCH2_VERSION}/contrib/ParseAndAddCatchTests.cmake" "${CATCH2_INCLUDEDIR}/ParseAndAddCatchTests.cmake")
|
||||
endif ()
|
||||
|
||||
add_library(Catch2::Catch2 INTERFACE IMPORTED)
|
||||
set_target_properties(Catch2::Catch2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CATCH2_INCLUDEDIR}")
|
22
conanfile.py
22
conanfile.py
@ -1,24 +1,14 @@
|
||||
from conans import ConanFile, CMake, tools
|
||||
import os
|
||||
from conans import ConanFile
|
||||
|
||||
|
||||
class MofilereaderConan(ConanFile):
|
||||
name = "MofileReader"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
license = "MIT"
|
||||
url = "https://github.com/AnotherFoxGuy/conan-MofileReader/"
|
||||
url = "https://github.com/AnotherFoxGuy/MofileReader/"
|
||||
description = "This API lets you read .mo-Files and use their content just as you would do with GNUs gettext."
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
exports_sources = "include*", "src*", "CMakeLists.txt"
|
||||
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
exports_sources = "include*"
|
||||
|
||||
def package(self):
|
||||
cmake = CMake(self)
|
||||
cmake.install()
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.libs = tools.collect_libs(self)
|
||||
self.copy("*.hpp", "include", "include")
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* moFileReader - A simple .mo-File-Reader
|
||||
* Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
* Copyright (C) 2018 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The names of its contributors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __MOFILECONFIG_H_INCLUDED__
|
||||
#define __MOFILECONFIG_H_INCLUDED__
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Defines an export-macro when compiling as dll on woe32.
|
||||
//-------------------------------------------------------------
|
||||
#if defined(MOFILE_EXPORTS) && defined (WIN32)
|
||||
# define MOEXPORT __declspec(dllexport)
|
||||
#elif defined (MOFILE_IMPORT) && defined(WIN32)
|
||||
# define MOEXPORT __declspec(dllimport)
|
||||
#else
|
||||
# define MOEXPORT
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Path-Seperators are different on other OS.
|
||||
//-------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
# define moPATHSEP std::string("\\")
|
||||
#else
|
||||
# define moPATHSEP std::string("/")
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Defines the beginning of the namespace moFileLib.
|
||||
//-------------------------------------------------------------
|
||||
#define MO_BEGIN_NAMESPACE namespace moFileLib{
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Ends the current namespace.
|
||||
//-------------------------------------------------------------
|
||||
#define MO_END_NAMESPACE }
|
||||
|
||||
|
||||
|
||||
#endif /* __MOFILECONFIG_H_INCLUDED__ */
|
@ -1,477 +0,0 @@
|
||||
/*
|
||||
* moFileReader - A simple .mo-File-Reader
|
||||
* Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
* Copyright (C) 2018 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The names of its contributors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __MOFILEREADER_H_INCLUDED__
|
||||
#define __MOFILEREADER_H_INCLUDED__
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <cstring> // this is for memset when compiling with gcc.
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef __MOFILECONFIG_H_INCLUDED__
|
||||
# include "moFileConfig.h"
|
||||
#endif
|
||||
|
||||
/** \mainpage moFileReaderSDK
|
||||
*
|
||||
* <h2>Compilation via cmake</h2>
|
||||
*
|
||||
* - Make sure you have cmake installed and in your path. If not, go to http://www.cmake.org and get it.
|
||||
* - Switch to a Shell or commandline
|
||||
* - Run cmake in $INSTALLDIR\\build. See cmake --help for possible generators. Here are the available Options:
|
||||
* - COMPILE_DLL Setting this to ON will compile the library as a shared module. By default, a static library is built.
|
||||
* .
|
||||
* Example:
|
||||
* \code
|
||||
* cmake -G"MinGW Makefiles" -DCOMPILE_DLL=ON
|
||||
* cmake -G"Visual Studio 9 2008"
|
||||
* // etc
|
||||
* \endcode
|
||||
*
|
||||
* cmake will compile the library and moReader[.exe]-binary, which can do lookups in moFiles and export moFiles as HTML.
|
||||
* See moReader[.exe] --help for details.
|
||||
* You will find the libraries in %%projectdir%%/lib and the binary in %%projectdir%%/bin
|
||||
*
|
||||
*
|
||||
* <h2>Include in project</h2>
|
||||
*
|
||||
* The last option is to simply add moFileReader.cpp, moFileReader.h and moFileConfig.h to your project. Thats all you have to do.
|
||||
* You can safely exclude mo.cpp, since this file keeps the entry-points of the .exe and .dll only.
|
||||
*
|
||||
* <h2>Usage</h2>
|
||||
*
|
||||
* This is moFileReader, a simple gettext-replacement. The usage of this library is, hopefully, fairly simple:
|
||||
* \code
|
||||
*
|
||||
* // Instanciate the class
|
||||
* moFileLib::moFileReader reader;
|
||||
*
|
||||
* // Load a .mo-File.
|
||||
* if ( reader.ReadFile("myTranslationFile.mo") != moFileLib::moFileReader::EC_SUCCESS )
|
||||
* {
|
||||
* // Error Handling
|
||||
* }
|
||||
*
|
||||
* // Now, you can lookup the strings you stored in the .mo-File:
|
||||
* std::cout << reader.Lookup("MyTranslationString") << std::endl;
|
||||
*
|
||||
* \endcode
|
||||
* Thats all! This small code has no dependencies, except the C/C++-runtime of your compiler,
|
||||
* so it should work on all machines where a C++-runtime is provided.
|
||||
*
|
||||
* \note We do not yet support .mo-Files with reversed magic-numbers, since I don't have
|
||||
* a file to test it and I hate to release stuff I wasn't able to test.
|
||||
*
|
||||
* <h2>Changelog</h2>
|
||||
*
|
||||
* - Version 1.0.0
|
||||
* - Added new function: LookupWithContext
|
||||
* - Added unit-tests
|
||||
* - Added support for packaging with Conan
|
||||
* - Moved project to https://github.com/AnotherFoxGuy/MofileReader
|
||||
*
|
||||
* - Version 0.1.2
|
||||
* - Generic improvements to the documentation.
|
||||
* - Generic improvements to the code
|
||||
* - Fixed a bug in mo.cpp which caused the application not to print the help
|
||||
* message if only --export or --lookup where missing.
|
||||
* - Added -h, --help and -? to moReader[.exe]. It will print the help-screen.
|
||||
* - Added --version and -v to moReader[.exe]. It will print some informations about the program.
|
||||
* - Added --license to moReader[.exe]. This will print its license.
|
||||
* - --export gives now a feedback about success or failure.
|
||||
* - The HTML-Dump-Method outputs now the whole table from the empty msgid in a nice html-table, not only a few hardcoded.
|
||||
* - I had an issue-report that the Error-Constants can collide with foreign code under certain conditions,
|
||||
* so I added a patch which renamed the error-constants to more compatible names.
|
||||
*
|
||||
* - Version 0.1.1
|
||||
* - Added the ability to export mo's as HTML.
|
||||
* - Fixed a bug causing a crash when passing an invalid value to moFileReader::Lookup().
|
||||
* - Added a new file, moFileConfig.h, holding the macros for the project.
|
||||
* - Added the ability to be configured by cmake.
|
||||
* - Added some more inline-functions, which really enhance the singleton.
|
||||
*
|
||||
* - Version 0.1.0
|
||||
* - Initial Version and release to http://googlecode.com
|
||||
*
|
||||
*
|
||||
* <h2>Credits</h2>
|
||||
*
|
||||
* Gettext is part of the GNU-Tools and (C) by the <a href="http://fsf.org">Free Software Foundation</a>.\n
|
||||
* Visual C++ Express is a registered Trademark of Microsoft, One Microsoft Way, Redmond, USA.\n
|
||||
* moFileReader is using NSIS for creating the setup-package. \n
|
||||
* All other Trademarks are property of their respective owners. \n
|
||||
* \n
|
||||
* Thanks for using this piece of OpenSource-Software.\n
|
||||
* Submit patches and/or bugs on https://github.com/AnotherFoxGuy/MofileReader.
|
||||
* Send your flames, dumb comments etc to /dev/null, thank you.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
About Warning 4251:
|
||||
http://support.microsoft.com/default.aspx?scid=KB;EN-US;16.
|
||||
|
||||
I am aware of this warning and know how to deal with it.
|
||||
To avoid that derived projects are influenced by this warning
|
||||
I have deactivated it for your convinience.
|
||||
Note: This warning only occurs, when using this code as a DLL.
|
||||
*/
|
||||
#if defined(_MSC_VER) && ( defined(_EXPORT) || defined(MOFILE_IMPORT) )
|
||||
# pragma warning (disable:4251)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
/** \namespace moFileLib
|
||||
* \brief This is the only namespace of this small sourcecode.
|
||||
*/
|
||||
MO_BEGIN_NAMESPACE
|
||||
|
||||
const std::string g_css = \
|
||||
"\
|
||||
body {\
|
||||
background-color: black;\
|
||||
color: silver;\
|
||||
}\
|
||||
table {\
|
||||
width: 80%;}\
|
||||
th {\
|
||||
background-color: orange;\
|
||||
color: black;\
|
||||
}\
|
||||
hr { color: red;width: 80%; size: 5px; }\
|
||||
a:link{color: gold;}\
|
||||
a:visited{color: grey;}\
|
||||
a:hover{color:blue;}\
|
||||
.copyleft{\
|
||||
font-size: 12px; \
|
||||
text-align: center;\
|
||||
}\
|
||||
";
|
||||
|
||||
/**
|
||||
* \brief Keeps the Description of translated and original strings.
|
||||
*
|
||||
*
|
||||
* To load a String from the file, we need its offset and its length.
|
||||
* This struct helps us grouping this information.
|
||||
*/
|
||||
struct moTranslationPairInformation
|
||||
{
|
||||
/// \brief Constructor
|
||||
moTranslationPairInformation()
|
||||
: m_orLength(0), m_orOffset(0),
|
||||
m_trLength(0), m_trOffset(0)
|
||||
{}
|
||||
|
||||
/// \brief Length of the Original String
|
||||
int m_orLength;
|
||||
|
||||
/// \brief Offset of the Original String (absolute)
|
||||
int m_orOffset;
|
||||
|
||||
/// \brief Length of the Translated String
|
||||
int m_trLength;
|
||||
|
||||
/// \brief Offset of the Translated String (absolute)
|
||||
int m_trOffset;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describes the "Header" of a .mo-File.
|
||||
*
|
||||
*
|
||||
* The File info keeps the header of a .mo-file and
|
||||
* a list of the string-descriptions.
|
||||
* The typedef is for the type of the string-list.
|
||||
* The constructor ensures, that all members get a nice
|
||||
* initial value.
|
||||
*/
|
||||
struct moFileInfo
|
||||
{
|
||||
/// \brief Type for the list of all Translation-Pair-Descriptions.
|
||||
typedef std::deque<moTranslationPairInformation> moTranslationPairList;
|
||||
|
||||
/// \brief Constructor
|
||||
moFileInfo()
|
||||
: m_magicNumber(0), m_fileVersion(0), m_numStrings(0),
|
||||
m_offsetOriginal(0), m_offsetTranslation(0), m_sizeHashtable(0),
|
||||
m_offsetHashtable(0), m_reversed(false)
|
||||
{}
|
||||
|
||||
/// \brief The Magic Number, compare it to g_MagicNumber.
|
||||
int m_magicNumber;
|
||||
|
||||
/// \brief The File Version, 0 atm according to the manpage.
|
||||
int m_fileVersion;
|
||||
|
||||
/// \brief Number of Strings in the .mo-file.
|
||||
int m_numStrings;
|
||||
|
||||
/// \brief Offset of the Table of the Original Strings
|
||||
int m_offsetOriginal;
|
||||
|
||||
/// \brief Offset of the Table of the Translated Strings
|
||||
int m_offsetTranslation;
|
||||
|
||||
/// \brief Size of 1 Entry in the Hashtable.
|
||||
int m_sizeHashtable;
|
||||
|
||||
/// \brief The Offset of the Hashtable.
|
||||
int m_offsetHashtable;
|
||||
|
||||
/** \brief Tells you if the bytes are reversed
|
||||
* \note When this is true, the bytes are reversed and the Magic number is like g_MagicReversed
|
||||
*/
|
||||
bool m_reversed;
|
||||
|
||||
/// \brief A list containing offset and length of the strings in the file.
|
||||
moTranslationPairList m_translationPairInformation;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief This class is a gettext-replacement.
|
||||
*
|
||||
*
|
||||
* The usage is quite simple:\n
|
||||
* Tell the class which .mo-file it shall load via
|
||||
* moFileReader::ReadFile(). The method will attempt to load
|
||||
* the file, all translations will be stored in memory.
|
||||
* Afterwards you can lookup the strings with moFileReader::Lookup() just
|
||||
* like you would do with gettext.
|
||||
* Additionally, you can call moFileReader::ReadFile() for as much files as you
|
||||
* like. But please be aware, that if there are duplicated keys (original strings),
|
||||
* that they will replace each other in the lookup-table. There is no check done, if a
|
||||
* key already exists.
|
||||
*
|
||||
* \note If you add "Lookup" to the keywords of the gettext-parser (like poEdit),
|
||||
* it will recognize the Strings loaded with an instance of this class.
|
||||
* \note I strongly recommend poEdit from Vaclav Slavik for editing .po-Files,
|
||||
* get it at http://poedit.net for various systems :).
|
||||
*/
|
||||
class MOEXPORT moFileReader
|
||||
{
|
||||
protected:
|
||||
/// \brief Type for the map which holds the translation-pairs later.
|
||||
typedef std::map<std::string, std::string> moLookupList;
|
||||
|
||||
public:
|
||||
|
||||
/// \brief The Magic Number describes the endianess of bytes on the system.
|
||||
static const long MagicNumber = 0x950412DE;
|
||||
|
||||
/// \brief If the Magic Number is Reversed, we need to swap the bytes.
|
||||
static const long MagicReversed = 0xDE120495;
|
||||
|
||||
/// \brief The possible errorcodes for methods of this class
|
||||
enum eErrorCode
|
||||
{
|
||||
/// \brief Indicated success
|
||||
EC_SUCCESS = 0,
|
||||
|
||||
/// \brief Indicates an error
|
||||
EC_ERROR,
|
||||
|
||||
/// \brief The given File was not found.
|
||||
EC_FILENOTFOUND,
|
||||
|
||||
/// \brief The file is invalid.
|
||||
EC_FILEINVALID,
|
||||
|
||||
/// \brief Empty Lookup-Table (returned by ExportAsHTML())
|
||||
EC_TABLEEMPTY,
|
||||
|
||||
/// \brief The magic number did not match
|
||||
EC_MAGICNUMBER_NOMATCH,
|
||||
|
||||
/**
|
||||
* \brief The magic number is reversed.
|
||||
* \note This is an error until the class supports it.
|
||||
*/
|
||||
EC_MAGICNUMBER_REVERSED,
|
||||
};
|
||||
|
||||
/** \brief Reads a .mo-file
|
||||
* \param[in] _filename The path to the file to load.
|
||||
* \return SUCCESS on success or one of the other error-codes in eErrorCode on error.
|
||||
*
|
||||
* This is the core-feature. This method loads the .mo-file and stores
|
||||
* all translation-pairs in a map. You can access this map via the method
|
||||
* moFileReader::Lookup().
|
||||
*/
|
||||
virtual moFileReader::eErrorCode ParseData(std::string data);
|
||||
|
||||
/** \brief Reads a .mo-file
|
||||
* \param[in] _filename The path to the file to load.
|
||||
* \return SUCCESS on success or one of the other error-codes in eErrorCode on error.
|
||||
*
|
||||
* This is the core-feature. This method loads the .mo-file and stores
|
||||
* all translation-pairs in a map. You can access this map via the method
|
||||
* moFileReader::Lookup().
|
||||
*/
|
||||
virtual eErrorCode ReadFile(const char* filename);
|
||||
|
||||
/** \brief Returns the searched translation or returns the input.
|
||||
* \param[in] id The id of the translation to search for.
|
||||
* \return The value you passed in via _id or the translated string.
|
||||
*/
|
||||
virtual std::string Lookup( const char* id ) const;
|
||||
|
||||
/** \brief Returns the searched translation or returns the input, restricted to the context given by context.
|
||||
* See https://www.gnu.org/software/gettext/manual/html_node/Contexts.html for more info.
|
||||
* \param[in] context Restrict to the context given.
|
||||
* \param[in] id The id of the translation to search for.
|
||||
* \return The value you passed in via _id or the translated string.
|
||||
*/
|
||||
virtual std::string LookupWithContext (const char* context, const char* id) const;
|
||||
|
||||
|
||||
/// \brief Returns the Error Description.
|
||||
virtual const std::string& GetErrorDescription() const;
|
||||
|
||||
/// \brief Empties the Lookup-Table.
|
||||
virtual void ClearTable();
|
||||
|
||||
/** \brief Returns the Number of Entries in our Lookup-Table.
|
||||
* \note The mo-File-table always contains an empty msgid, which contains informations
|
||||
* about the tranlsation-project. So the real number of strings is always minus 1.
|
||||
*/
|
||||
virtual unsigned int GetNumStrings() const;
|
||||
|
||||
/** \brief Exports the whole content of the .mo-File as .html
|
||||
* \param[in] infile The .mo-File to export.
|
||||
* \param[in] filename Where to store the .html-file. If empty, the path and filename of the _infile with .html appended.
|
||||
* \param[in,out] css The css-script for the visual style of the
|
||||
* file, in case you don't like mine ;).
|
||||
* \see g_css for the possible and used css-values.
|
||||
*/
|
||||
static eErrorCode ExportAsHTML(const std::string infile, const std::string filename = "", const std::string css = g_css );
|
||||
|
||||
protected:
|
||||
/// \brief Keeps the last error as String.
|
||||
std::string m_error;
|
||||
|
||||
/** \brief Swap the endianness of a 4 byte WORD.
|
||||
* \param[in] in The value to swap.
|
||||
* \return The swapped value.
|
||||
*/
|
||||
unsigned long SwapBytes(unsigned long in);
|
||||
|
||||
private:
|
||||
// Holds the lookup-table
|
||||
moLookupList m_lookup;
|
||||
|
||||
void MakeHtmlConform(std::string& _inout);
|
||||
bool GetPoEditorString(const char* _buffer, std::string& _name, std::string& _value);
|
||||
void Trim(std::string& _in);
|
||||
};
|
||||
|
||||
/** \brief Convience Class
|
||||
*
|
||||
*
|
||||
* This class derives from moFileReader and builds a singleton to access its methods
|
||||
* in a global manner.
|
||||
* \note This class is a Singleton. Please access it via moFileReaderSingleton::GetInstance()
|
||||
* or use the provided wrappers:\n
|
||||
* - moReadMoFile()
|
||||
* - _()
|
||||
* - moFileClearTable()
|
||||
* - moFileGetErrorDescription()
|
||||
* - moFileGetNumStrings();
|
||||
*/
|
||||
class MOEXPORT moFileReaderSingleton : public moFileReader
|
||||
{
|
||||
private:
|
||||
// Private Contructor and Copy-Constructor to avoid
|
||||
// that this class is instanced.
|
||||
moFileReaderSingleton();
|
||||
moFileReaderSingleton(const moFileReaderSingleton&);
|
||||
moFileReaderSingleton& operator=(const moFileReaderSingleton&);
|
||||
|
||||
public:
|
||||
/** \brief Singleton-Accessor.
|
||||
* \return A static instance of moFileReaderSingleton.
|
||||
*/
|
||||
static moFileReaderSingleton& GetInstance();
|
||||
};
|
||||
|
||||
/** \brief Reads the .mo-File.
|
||||
* \param[in] _filename The path to the file to use.
|
||||
* \see moFileReader::ReadFile() for details.
|
||||
*/
|
||||
inline moFileReader::eErrorCode moReadMoFile(const char* _filename)
|
||||
{
|
||||
moFileReader::eErrorCode r = moFileReaderSingleton::GetInstance().ReadFile(_filename);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \brief Looks for the spec. string to translate.
|
||||
* \param[in] id The string-id to search.
|
||||
* \return The translation if found, otherwise it returns id.
|
||||
*/
|
||||
inline std::string _(const char* id)
|
||||
{
|
||||
std::string r = moFileReaderSingleton::GetInstance().Lookup(id);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// \brief Resets the Lookup-Table.
|
||||
inline void moFileClearTable()
|
||||
{
|
||||
moFileReaderSingleton::GetInstance().ClearTable();
|
||||
}
|
||||
|
||||
/// \brief Returns the last known error as string or an empty class.
|
||||
inline std::string moFileGetErrorDescription()
|
||||
{
|
||||
std::string r = moFileReaderSingleton::GetInstance().GetErrorDescription();
|
||||
return r;
|
||||
}
|
||||
|
||||
/// \brief Returns the number of entries loaded from the .mo-File.
|
||||
inline int moFileGetNumStrings()
|
||||
{
|
||||
int r = moFileReaderSingleton::GetInstance().GetNumStrings();
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (default:4251)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
MO_END_NAMESPACE
|
||||
|
||||
#endif /* __MOFILEREADER_H_INCLUDED__ */
|
901
include/moFileReader.hpp
Normal file
901
include/moFileReader.hpp
Normal file
@ -0,0 +1,901 @@
|
||||
/*
|
||||
* moFileReader - A simple .mo-File-Reader
|
||||
* Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
* Copyright (C) 2018-2021 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The names of its contributors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __MOFILEREADER_SINGLE_INCLUDE_H_INCLUDED__
|
||||
#define __MOFILEREADER_SINGLE_INCLUDE_H_INCLUDED__
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4267)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include <cstring> // this is for memset when compiling with gcc.
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Path-Seperators are different on other OS.
|
||||
//-------------------------------------------------------------
|
||||
#ifndef moPATHSEP
|
||||
#ifdef WIN32
|
||||
#define moPATHSEP std::string("\\")
|
||||
#else
|
||||
#define moPATHSEP std::string("/")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Defines the beginning of the namespace moFileLib.
|
||||
//-------------------------------------------------------------
|
||||
#ifndef MO_BEGIN_NAMESPACE
|
||||
#define MO_BEGIN_NAMESPACE \
|
||||
namespace moFileLib \
|
||||
{
|
||||
#endif
|
||||
//-------------------------------------------------------------
|
||||
// Ends the current namespace.
|
||||
//-------------------------------------------------------------
|
||||
#ifndef MO_END_NAMESPACE
|
||||
#define MO_END_NAMESPACE }
|
||||
#endif
|
||||
|
||||
/** \mainpage moFileReaderSDK
|
||||
*
|
||||
*
|
||||
* <h2>Include in project</h2>
|
||||
*
|
||||
* Usage of this library is quite easy, simply add moFileReader.hpp to your project. Thats all you have to do.
|
||||
* You can safely exclude mo.cpp, since this file keeps the entry-points of the .exe only.
|
||||
*
|
||||
* <h2>Usage</h2>
|
||||
*
|
||||
* This is moFileReader, a simple gettext-replacement. The usage of this library is, hopefully, fairly simple:
|
||||
* \code
|
||||
*
|
||||
* // Instanciate the class
|
||||
* moFileLib::moFileReader reader;
|
||||
*
|
||||
* // Load a .mo-File.
|
||||
* if ( reader.ReadFile("myTranslationFile.mo") != moFileLib::moFileReader::EC_SUCCESS )
|
||||
* {
|
||||
* // Error Handling
|
||||
* }
|
||||
*
|
||||
* // Now, you can lookup the strings you stored in the .mo-File:
|
||||
* std::cout << reader.Lookup("MyTranslationString") << std::endl;
|
||||
*
|
||||
* \endcode
|
||||
* Thats all! This small code has no dependencies, except the C/C++-runtime of your compiler,
|
||||
* so it should work on all machines where a C++-runtime is provided.
|
||||
*
|
||||
* \note We do not yet support .mo-Files with reversed magic-numbers, since I don't have
|
||||
* a file to test it and I hate to release stuff I wasn't able to test.
|
||||
*
|
||||
* <h2>Changelog</h2>
|
||||
*
|
||||
* - Version 1.1.0
|
||||
* - Converted library to a header-only library
|
||||
*
|
||||
* - Version 1.0.0
|
||||
* - Added new function: LookupWithContext
|
||||
* - Added unit-tests
|
||||
* - Added support for packaging with Conan
|
||||
* - Moved project to https://github.com/AnotherFoxGuy/MofileReader
|
||||
*
|
||||
* - Version 0.1.2
|
||||
* - Generic improvements to the documentation.
|
||||
* - Generic improvements to the code
|
||||
* - Fixed a bug in mo.cpp which caused the application not to print the help
|
||||
* message if only --export or --lookup where missing.
|
||||
* - Added -h, --help and -? to moReader[.exe]. It will print the help-screen.
|
||||
* - Added --version and -v to moReader[.exe]. It will print some informations about the program.
|
||||
* - Added --license to moReader[.exe]. This will print its license.
|
||||
* - --export gives now a feedback about success or failure.
|
||||
* - The HTML-Dump-Method outputs now the whole table from the empty msgid in a nice html-table, not only a few hardcoded.
|
||||
* - I had an issue-report that the Error-Constants can collide with foreign code under certain conditions,
|
||||
* so I added a patch which renamed the error-constants to more compatible names.
|
||||
*
|
||||
* - Version 0.1.1
|
||||
* - Added the ability to export mo's as HTML.
|
||||
* - Fixed a bug causing a crash when passing an invalid value to moFileReader::Lookup().
|
||||
* - Added a new file, moFileConfig.h, holding the macros for the project.
|
||||
* - Added the ability to be configured by cmake.
|
||||
* - Added some more inline-functions, which really enhance the singleton.
|
||||
*
|
||||
* - Version 0.1.0
|
||||
* - Initial Version and release to http://googlecode.com
|
||||
*
|
||||
*
|
||||
* <h2>Credits</h2>
|
||||
*
|
||||
* Gettext is part of the GNU-Tools and (C) by the <a href="http://fsf.org">Free Software Foundation</a>.\n
|
||||
* Visual C++ Express is a registered Trademark of Microsoft, One Microsoft Way, Redmond, USA.\n
|
||||
* moFileReader is using NSIS for creating the setup-package. \n
|
||||
* All other Trademarks are property of their respective owners. \n
|
||||
* \n
|
||||
* Thanks for using this piece of OpenSource-Software.\n
|
||||
* Submit patches and/or bugs on https://github.com/AnotherFoxGuy/MofileReader.
|
||||
* Send your flames, dumb comments etc to /dev/null, thank you.
|
||||
*/
|
||||
|
||||
/** \namespace moFileLib
|
||||
* \brief This is the only namespace of this small sourcecode.
|
||||
*/
|
||||
MO_BEGIN_NAMESPACE
|
||||
|
||||
const std::string g_css = R"(
|
||||
body {
|
||||
background-color: black;
|
||||
color: silver;
|
||||
}
|
||||
table {
|
||||
width: 80%;
|
||||
}
|
||||
th {
|
||||
background-color: orange;
|
||||
color: black;
|
||||
}
|
||||
hr {
|
||||
color: red;
|
||||
width: 80%;
|
||||
size: 5px;
|
||||
}
|
||||
a:link{
|
||||
color: gold;
|
||||
}
|
||||
a:visited{
|
||||
color: grey;
|
||||
}
|
||||
a:hover{
|
||||
color:blue;
|
||||
}
|
||||
.copyleft{
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
})";
|
||||
|
||||
/**
|
||||
* \brief Keeps the Description of translated and original strings.
|
||||
*
|
||||
*
|
||||
* To load a String from the file, we need its offset and its length.
|
||||
* This struct helps us grouping this information.
|
||||
*/
|
||||
struct moTranslationPairInformation
|
||||
{
|
||||
/// \brief Constructor
|
||||
moTranslationPairInformation() : m_orLength(0), m_orOffset(0), m_trLength(0), m_trOffset(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief Length of the Original String
|
||||
int m_orLength;
|
||||
|
||||
/// \brief Offset of the Original String (absolute)
|
||||
int m_orOffset;
|
||||
|
||||
/// \brief Length of the Translated String
|
||||
int m_trLength;
|
||||
|
||||
/// \brief Offset of the Translated String (absolute)
|
||||
int m_trOffset;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describes the "Header" of a .mo-File.
|
||||
*
|
||||
*
|
||||
* The File info keeps the header of a .mo-file and
|
||||
* a list of the string-descriptions.
|
||||
* The typedef is for the type of the string-list.
|
||||
* The constructor ensures, that all members get a nice
|
||||
* initial value.
|
||||
*/
|
||||
struct moFileInfo
|
||||
{
|
||||
/// \brief Type for the list of all Translation-Pair-Descriptions.
|
||||
typedef std::deque<moTranslationPairInformation> moTranslationPairList;
|
||||
|
||||
/// \brief Constructor
|
||||
moFileInfo()
|
||||
: m_magicNumber(0), m_fileVersion(0), m_numStrings(0), m_offsetOriginal(0), m_offsetTranslation(0), m_sizeHashtable(0),
|
||||
m_offsetHashtable(0), m_reversed(false)
|
||||
{
|
||||
}
|
||||
|
||||
/// \brief The Magic Number, compare it to g_MagicNumber.
|
||||
int m_magicNumber;
|
||||
|
||||
/// \brief The File Version, 0 atm according to the manpage.
|
||||
int m_fileVersion;
|
||||
|
||||
/// \brief Number of Strings in the .mo-file.
|
||||
int m_numStrings;
|
||||
|
||||
/// \brief Offset of the Table of the Original Strings
|
||||
int m_offsetOriginal;
|
||||
|
||||
/// \brief Offset of the Table of the Translated Strings
|
||||
int m_offsetTranslation;
|
||||
|
||||
/// \brief Size of 1 Entry in the Hashtable.
|
||||
int m_sizeHashtable;
|
||||
|
||||
/// \brief The Offset of the Hashtable.
|
||||
int m_offsetHashtable;
|
||||
|
||||
/** \brief Tells you if the bytes are reversed
|
||||
* \note When this is true, the bytes are reversed and the Magic number is like g_MagicReversed
|
||||
*/
|
||||
bool m_reversed;
|
||||
|
||||
/// \brief A list containing offset and length of the strings in the file.
|
||||
moTranslationPairList m_translationPairInformation;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief This class is a gettext-replacement.
|
||||
*
|
||||
*
|
||||
* The usage is quite simple:\n
|
||||
* Tell the class which .mo-file it shall load via
|
||||
* moFileReader::ReadFile(). The method will attempt to load
|
||||
* the file, all translations will be stored in memory.
|
||||
* Afterwards you can lookup the strings with moFileReader::Lookup() just
|
||||
* like you would do with gettext.
|
||||
* Additionally, you can call moFileReader::ReadFile() for as much files as you
|
||||
* like. But please be aware, that if there are duplicated keys (original strings),
|
||||
* that they will replace each other in the lookup-table. There is no check done, if a
|
||||
* key already exists.
|
||||
*
|
||||
* \note If you add "Lookup" to the keywords of the gettext-parser (like poEdit),
|
||||
* it will recognize the Strings loaded with an instance of this class.
|
||||
* \note I strongly recommend poEdit from Vaclav Slavik for editing .po-Files,
|
||||
* get it at http://poedit.net for various systems :).
|
||||
*/
|
||||
class moFileReader
|
||||
{
|
||||
protected:
|
||||
/// \brief Type for the map which holds the translation-pairs later.
|
||||
typedef std::map<std::string, std::string> moLookupList;
|
||||
|
||||
public:
|
||||
/// \brief The Magic Number describes the endianess of bytes on the system.
|
||||
static const long MagicNumber = 0x950412DE;
|
||||
|
||||
/// \brief If the Magic Number is Reversed, we need to swap the bytes.
|
||||
static const long MagicReversed = 0xDE120495;
|
||||
|
||||
/// \brief The possible errorcodes for methods of this class
|
||||
enum eErrorCode
|
||||
{
|
||||
/// \brief Indicated success
|
||||
EC_SUCCESS = 0,
|
||||
|
||||
/// \brief Indicates an error
|
||||
EC_ERROR,
|
||||
|
||||
/// \brief The given File was not found.
|
||||
EC_FILENOTFOUND,
|
||||
|
||||
/// \brief The file is invalid.
|
||||
EC_FILEINVALID,
|
||||
|
||||
/// \brief Empty Lookup-Table (returned by ExportAsHTML())
|
||||
EC_TABLEEMPTY,
|
||||
|
||||
/// \brief The magic number did not match
|
||||
EC_MAGICNUMBER_NOMATCH,
|
||||
|
||||
/**
|
||||
* \brief The magic number is reversed.
|
||||
* \note This is an error until the class supports it.
|
||||
*/
|
||||
EC_MAGICNUMBER_REVERSED,
|
||||
};
|
||||
|
||||
/** \brief Reads a .mo-file
|
||||
* \param[in] _filename The path to the file to load.
|
||||
* \return SUCCESS on success or one of the other error-codes in eErrorCode on error.
|
||||
*
|
||||
* This is the core-feature. This method loads the .mo-file and stores
|
||||
* all translation-pairs in a map. You can access this map via the method
|
||||
* moFileReader::Lookup().
|
||||
*/
|
||||
moFileReader::eErrorCode ParseData(const std::string &data)
|
||||
{
|
||||
// Creating a file-description.
|
||||
moFileInfo moInfo;
|
||||
|
||||
// Reference to the List inside moInfo.
|
||||
moFileInfo::moTranslationPairList &TransPairInfo = moInfo.m_translationPairInformation;
|
||||
|
||||
// Opening the file.
|
||||
std::stringstream stream(data);
|
||||
|
||||
// Read in all the 4 bytes of fire-magic, offsets and stuff...
|
||||
stream.read((char *)&moInfo.m_magicNumber, 4);
|
||||
stream.read((char *)&moInfo.m_fileVersion, 4);
|
||||
stream.read((char *)&moInfo.m_numStrings, 4);
|
||||
stream.read((char *)&moInfo.m_offsetOriginal, 4);
|
||||
stream.read((char *)&moInfo.m_offsetTranslation, 4);
|
||||
stream.read((char *)&moInfo.m_sizeHashtable, 4);
|
||||
stream.read((char *)&moInfo.m_offsetHashtable, 4);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Checking the Magic Number
|
||||
if (MagicNumber != moInfo.m_magicNumber)
|
||||
{
|
||||
if (MagicReversed != moInfo.m_magicNumber)
|
||||
{
|
||||
m_error = "The Magic Number does not match in all cases!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_MAGICNUMBER_NOMATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
moInfo.m_reversed = true;
|
||||
m_error = "Magic Number is reversed. We do not support this yet!";
|
||||
return moFileReader::EC_MAGICNUMBER_REVERSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we search all Length & Offsets of the original strings
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
moTranslationPairInformation _str;
|
||||
stream.read((char *)&_str.m_orLength, 4);
|
||||
stream.read((char *)&_str.m_orOffset, 4);
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
TransPairInfo.push_back(_str);
|
||||
}
|
||||
|
||||
// Get all Lengths & Offsets of the translated strings
|
||||
// Be aware: The Descriptors already exist in our list, so we just mod. refs from the deque.
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
moTranslationPairInformation &_str = TransPairInfo[i];
|
||||
stream.read((char *)&_str.m_trLength, 4);
|
||||
stream.read((char *)&_str.m_trOffset, 4);
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally you would read the hash-table here, but we don't use it. :)
|
||||
|
||||
// Now to the interesting part, we read the strings-pairs now
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
// We need a length of +1 to catch the trailing \0.
|
||||
int orLength = TransPairInfo[i].m_orLength + 1;
|
||||
int trLength = TransPairInfo[i].m_trLength + 1;
|
||||
|
||||
int orOffset = TransPairInfo[i].m_orOffset;
|
||||
int trOffset = TransPairInfo[i].m_trOffset;
|
||||
|
||||
// Original
|
||||
char *original = new char[orLength];
|
||||
memset(original, 0, sizeof(char) * orLength);
|
||||
|
||||
stream.seekg(orOffset);
|
||||
stream.read(original, orLength);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Translation
|
||||
char *translation = new char[trLength];
|
||||
memset(translation, 0, sizeof(char) * trLength);
|
||||
|
||||
stream.seekg(trOffset);
|
||||
stream.read(translation, trLength);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Store it in the map.
|
||||
m_lookup[std::string(original)] = std::string(translation);
|
||||
|
||||
// Cleanup...
|
||||
delete[] original;
|
||||
delete[] translation;
|
||||
}
|
||||
|
||||
// Done :)
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
/** \brief Reads a .mo-file
|
||||
* \param[in] _filename The path to the file to load.
|
||||
* \return SUCCESS on success or one of the other error-codes in eErrorCode on error.
|
||||
*
|
||||
* This is the core-feature. This method loads the .mo-file and stores
|
||||
* all translation-pairs in a map. You can access this map via the method
|
||||
* moFileReader::Lookup().
|
||||
*/
|
||||
eErrorCode ReadFile(const char *filename)
|
||||
{
|
||||
// Creating a file-description.
|
||||
moFileInfo moInfo;
|
||||
|
||||
// Reference to the List inside moInfo.
|
||||
moFileInfo::moTranslationPairList &TransPairInfo = moInfo.m_translationPairInformation;
|
||||
|
||||
// Opening the file.
|
||||
std::ifstream stream(filename, std::ios_base::binary | std::ios_base::in);
|
||||
if (!stream.is_open())
|
||||
{
|
||||
m_error = std::string("Cannot open File ") + std::string(filename);
|
||||
return moFileReader::EC_FILENOTFOUND;
|
||||
}
|
||||
|
||||
// Read in all the 4 bytes of fire-magic, offsets and stuff...
|
||||
stream.read((char *)&moInfo.m_magicNumber, 4);
|
||||
stream.read((char *)&moInfo.m_fileVersion, 4);
|
||||
stream.read((char *)&moInfo.m_numStrings, 4);
|
||||
stream.read((char *)&moInfo.m_offsetOriginal, 4);
|
||||
stream.read((char *)&moInfo.m_offsetTranslation, 4);
|
||||
stream.read((char *)&moInfo.m_sizeHashtable, 4);
|
||||
stream.read((char *)&moInfo.m_offsetHashtable, 4);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Checking the Magic Number
|
||||
if (MagicNumber != moInfo.m_magicNumber)
|
||||
{
|
||||
if (MagicReversed != moInfo.m_magicNumber)
|
||||
{
|
||||
m_error = "The Magic Number does not match in all cases!";
|
||||
// return moFileReader::EC_MAGICNUMBER_NOMATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
moInfo.m_reversed = true;
|
||||
m_error = "Magic Number is reversed. We do not support this yet!";
|
||||
return moFileReader::EC_MAGICNUMBER_REVERSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we search all Length & Offsets of the original strings
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
moTranslationPairInformation _str;
|
||||
stream.read((char *)&_str.m_orLength, 4);
|
||||
stream.read((char *)&_str.m_orOffset, 4);
|
||||
if (stream.bad())
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
TransPairInfo.push_back(_str);
|
||||
}
|
||||
|
||||
// Get all Lengths & Offsets of the translated strings
|
||||
// Be aware: The Descriptors already exist in our list, so we just mod. refs from the deque.
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
moTranslationPairInformation &_str = TransPairInfo[i];
|
||||
stream.read((char *)&_str.m_trLength, 4);
|
||||
stream.read((char *)&_str.m_trOffset, 4);
|
||||
if (stream.bad())
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally you would read the hash-table here, but we don't use it. :)
|
||||
|
||||
// Now to the interesting part, we read the strings-pairs now
|
||||
for (int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
// We need a length of +1 to catch the trailing \0.
|
||||
int orLength = TransPairInfo[i].m_orLength + 1;
|
||||
int trLength = TransPairInfo[i].m_trLength + 1;
|
||||
|
||||
int orOffset = TransPairInfo[i].m_orOffset;
|
||||
int trOffset = TransPairInfo[i].m_trOffset;
|
||||
|
||||
// Original
|
||||
char *original = new char[orLength];
|
||||
memset(original, 0, sizeof(char) * orLength);
|
||||
|
||||
stream.seekg(orOffset);
|
||||
stream.read(original, orLength);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Translation
|
||||
char *translation = new char[trLength];
|
||||
memset(translation, 0, sizeof(char) * trLength);
|
||||
|
||||
stream.seekg(trOffset);
|
||||
stream.read(translation, trLength);
|
||||
|
||||
if (stream.bad())
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Store it in the map.
|
||||
m_lookup[std::string(original)] = std::string(translation);
|
||||
|
||||
// Cleanup...
|
||||
delete[] original;
|
||||
delete[] translation;
|
||||
}
|
||||
|
||||
// Done :)
|
||||
stream.close();
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
/** \brief Returns the searched translation or returns the input.
|
||||
* \param[in] id The id of the translation to search for.
|
||||
* \return The value you passed in via _id or the translated string.
|
||||
*/
|
||||
std::string Lookup(const char *id) const
|
||||
{
|
||||
if (m_lookup.empty()) return id;
|
||||
auto iterator = m_lookup.find(id);
|
||||
|
||||
if (iterator == m_lookup.end()) { return id; }
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
/** \brief Returns the searched translation or returns the input, restricted to the context given by context.
|
||||
* See https://www.gnu.org/software/gettext/manual/html_node/Contexts.html for more info.
|
||||
* \param[in] context Restrict to the context given.
|
||||
* \param[in] id The id of the translation to search for.
|
||||
* \return The value you passed in via _id or the translated string.
|
||||
*/
|
||||
std::string LookupWithContext(const char *context, const char *id) const
|
||||
{
|
||||
std::string idName = context;
|
||||
idName += '\x04';
|
||||
idName += id;
|
||||
|
||||
if (m_lookup.empty()) return id;
|
||||
auto iterator = m_lookup.find(idName);
|
||||
|
||||
if (iterator == m_lookup.end()) { return id; }
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
/// \brief Returns the Error Description.
|
||||
const std::string &GetErrorDescription() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
/// \brief Empties the Lookup-Table.
|
||||
void ClearTable()
|
||||
{
|
||||
m_lookup.clear();
|
||||
}
|
||||
|
||||
/** \brief Returns the Number of Entries in our Lookup-Table.
|
||||
* \note The mo-File-table always contains an empty msgid, which contains informations
|
||||
* about the tranlsation-project. So the real number of strings is always minus 1.
|
||||
*/
|
||||
unsigned int GetNumStrings() const
|
||||
{
|
||||
return m_lookup.size();
|
||||
}
|
||||
|
||||
/** \brief Exports the whole content of the .mo-File as .html
|
||||
* \param[in] infile The .mo-File to export.
|
||||
* \param[in] filename Where to store the .html-file. If empty, the path and filename of the _infile with .html appended.
|
||||
* \param[in,out] css The css-script for the visual style of the
|
||||
* file, in case you don't like mine ;).
|
||||
* \see g_css for the possible and used css-values.
|
||||
*/
|
||||
static eErrorCode ExportAsHTML(const std::string &infile, const std::string &filename = "", const std::string &css = g_css)
|
||||
{
|
||||
// Read the file
|
||||
moFileReader reader;
|
||||
moFileReader::eErrorCode r = reader.ReadFile(infile.c_str());
|
||||
if (r != moFileReader::EC_SUCCESS) { return r; }
|
||||
if (reader.m_lookup.empty()) { return moFileReader::EC_TABLEEMPTY; }
|
||||
|
||||
// Beautify Output
|
||||
std::string fname;
|
||||
unsigned int pos = infile.find_last_of(moPATHSEP);
|
||||
if (pos != std::string::npos) { fname = infile.substr(pos + 1, infile.length()); }
|
||||
else
|
||||
{
|
||||
fname = infile;
|
||||
}
|
||||
|
||||
// if there is no filename given, we set it to the .mo + html, e.g. test.mo.html
|
||||
std::string htmlfile(filename);
|
||||
if (htmlfile.empty()) { htmlfile = infile + std::string(".html"); }
|
||||
|
||||
// Ok, now prepare output.
|
||||
std::ofstream stream(htmlfile.c_str());
|
||||
if (stream.is_open())
|
||||
{
|
||||
stream << R"(<!DOCTYPE HTML PUBLIC "- //W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">)"
|
||||
<< std::endl;
|
||||
stream << "<html><head><style type=\"text/css\">\n" << std::endl;
|
||||
stream << css << std::endl;
|
||||
stream << "</style>" << std::endl;
|
||||
stream << R"(<meta http-equiv="content-type" content="text/html; charset=utf-8">)" << std::endl;
|
||||
stream << "<title>Dump of " << fname << "</title></head>" << std::endl;
|
||||
stream << "<body>" << std::endl;
|
||||
stream << "<center>" << std::endl;
|
||||
stream << "<h1>" << fname << "</h1>" << std::endl;
|
||||
stream << R"(<table border="1"><th colspan="2">Project Info</th>)" << std::endl;
|
||||
|
||||
std::stringstream parsee;
|
||||
parsee << reader.Lookup("");
|
||||
|
||||
while (!parsee.eof())
|
||||
{
|
||||
char buffer[1024];
|
||||
parsee.getline(buffer, 1024);
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
reader.GetPoEditorString(buffer, name, value);
|
||||
if (!(name.empty() || value.empty()))
|
||||
{
|
||||
stream << "<tr><td>" << name << "</td><td>" << value << "</td></tr>" << std::endl;
|
||||
}
|
||||
}
|
||||
stream << "</table>" << std::endl;
|
||||
stream << "<hr noshade/>" << std::endl;
|
||||
|
||||
// Now output the content
|
||||
stream << R"(<table border="1"><th colspan="2">Content</th>)" << std::endl;
|
||||
for (const auto &it : reader.m_lookup)
|
||||
{
|
||||
if (!it.first.empty()) // Skip the empty msgid, its the table we handled above.
|
||||
{
|
||||
stream << "<tr><td>" << it.first << "</td><td>" << it.second << "</td></tr>" << std::endl;
|
||||
}
|
||||
}
|
||||
stream << "</table><br/>" << std::endl;
|
||||
|
||||
stream << "</center>" << std::endl;
|
||||
stream << "<div class=\"copyleft\">File generated by <a href=\"https://github.com/AnotherFoxGuy/MofileReader\" "
|
||||
"target=\"_blank\">moFileReaderSDK</a></div>"
|
||||
<< std::endl;
|
||||
stream << "</body></html>" << std::endl;
|
||||
stream.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
return moFileReader::EC_FILENOTFOUND;
|
||||
}
|
||||
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Keeps the last error as String.
|
||||
std::string m_error;
|
||||
|
||||
/** \brief Swap the endianness of a 4 byte WORD.
|
||||
* \param[in] in The value to swap.
|
||||
* \return The swapped value.
|
||||
*/
|
||||
unsigned long SwapBytes(unsigned long in)
|
||||
{
|
||||
unsigned long b0 = (in >> 0) & 0xff;
|
||||
unsigned long b1 = (in >> 8) & 0xff;
|
||||
unsigned long b2 = (in >> 16) & 0xff;
|
||||
unsigned long b3 = (in >> 24) & 0xff;
|
||||
|
||||
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
}
|
||||
|
||||
private:
|
||||
// Holds the lookup-table
|
||||
moLookupList m_lookup;
|
||||
|
||||
// Replaces < with ( to satisfy html-rules.
|
||||
static void MakeHtmlConform(std::string &_inout)
|
||||
{
|
||||
std::string temp = _inout;
|
||||
for (unsigned int i = 0; i < temp.length(); i++)
|
||||
{
|
||||
if (temp[i] == '>') { _inout.replace(i, 1, ")"); }
|
||||
if (temp[i] == '<') { _inout.replace(i, 1, "("); }
|
||||
}
|
||||
}
|
||||
|
||||
// Extracts a value-pair from the po-edit-information
|
||||
bool GetPoEditorString(const char *_buffer, std::string &_name, std::string &_value)
|
||||
{
|
||||
std::string line(_buffer);
|
||||
size_t first = line.find_first_of(':');
|
||||
|
||||
if (first != std::string::npos)
|
||||
{
|
||||
_name = line.substr(0, first);
|
||||
_value = line.substr(first + 1, line.length());
|
||||
|
||||
// Replace <> with () for Html-Conformity.
|
||||
MakeHtmlConform(_value);
|
||||
MakeHtmlConform(_name);
|
||||
|
||||
// Remove spaces from front and end.
|
||||
Trim(_value);
|
||||
Trim(_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removes spaces from front and end.
|
||||
static void Trim(std::string &_in)
|
||||
{
|
||||
while (_in[0] == ' ')
|
||||
{
|
||||
_in = _in.substr(1, _in.length());
|
||||
}
|
||||
while (_in[_in.length()] == ' ')
|
||||
{
|
||||
_in = _in.substr(0, _in.length() - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief Convience Class
|
||||
*
|
||||
*
|
||||
* This class derives from moFileReader and builds a singleton to access its methods
|
||||
* in a global manner.
|
||||
* \note This class is a Singleton. Please access it via moFileReaderSingleton::GetInstance()
|
||||
* or use the provided wrappers:\n
|
||||
* - moReadMoFile()
|
||||
* - _()
|
||||
* - moFileClearTable()
|
||||
* - moFileGetErrorDescription()
|
||||
* - moFileGetNumStrings();
|
||||
*/
|
||||
class moFileReaderSingleton : public moFileReader
|
||||
{
|
||||
private:
|
||||
// Private Contructor and Copy-Constructor to avoid
|
||||
// that this class is instanced.
|
||||
moFileReaderSingleton()
|
||||
{
|
||||
}
|
||||
|
||||
moFileReaderSingleton(const moFileReaderSingleton &);
|
||||
|
||||
moFileReaderSingleton &operator=(const moFileReaderSingleton &)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
/** \brief Singleton-Accessor.
|
||||
* \return A static instance of moFileReaderSingleton.
|
||||
*/
|
||||
static moFileReaderSingleton &GetInstance()
|
||||
{
|
||||
static moFileReaderSingleton theoneandonly;
|
||||
return theoneandonly;
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief Reads the .mo-File.
|
||||
* \param[in] _filename The path to the file to use.
|
||||
* \see moFileReader::ReadFile() for details.
|
||||
*/
|
||||
inline moFileReader::eErrorCode moReadMoFile(const char *_filename)
|
||||
{
|
||||
moFileReader::eErrorCode r = moFileReaderSingleton::GetInstance().ReadFile(_filename);
|
||||
return r;
|
||||
}
|
||||
|
||||
/** \brief Looks for the spec. string to translate.
|
||||
* \param[in] id The string-id to search.
|
||||
* \return The translation if found, otherwise it returns id.
|
||||
*/
|
||||
inline std::string _(const char *id)
|
||||
{
|
||||
std::string r = moFileReaderSingleton::GetInstance().Lookup(id);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// \brief Resets the Lookup-Table.
|
||||
inline void moFileClearTable()
|
||||
{
|
||||
moFileReaderSingleton::GetInstance().ClearTable();
|
||||
}
|
||||
|
||||
/// \brief Returns the last known error as string or an empty class.
|
||||
inline std::string moFileGetErrorDescription()
|
||||
{
|
||||
std::string r = moFileReaderSingleton::GetInstance().GetErrorDescription();
|
||||
return r;
|
||||
}
|
||||
|
||||
/// \brief Returns the number of entries loaded from the .mo-File.
|
||||
inline int moFileGetNumStrings()
|
||||
{
|
||||
int r = moFileReaderSingleton::GetInstance().GetNumStrings();
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(default : 4251)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
MO_END_NAMESPACE
|
||||
|
||||
#endif /* __MOFILEREADER_SINGLE_INCLUDE_H_INCLUDED__ */
|
106
src/mo.cpp
106
src/mo.cpp
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* moFileReader - A simple .mo-File-Reader
|
||||
* Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
* Copyright (C) 2018 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* Copyright (C) 2018-2021 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -31,9 +31,10 @@
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "moFileReader.h"
|
||||
#include <iostream>
|
||||
#include "moFileReader.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
@ -41,7 +42,7 @@
|
||||
|
||||
using namespace moFileLib;
|
||||
|
||||
void Usage(const std::string appname)
|
||||
void Usage(const std::string& appname)
|
||||
{
|
||||
std::cout << "Usage: " << std::endl;
|
||||
std::cout << appname << " <option> <params>" << std::endl;
|
||||
@ -59,37 +60,38 @@ void Usage(const std::string appname)
|
||||
|
||||
void PrintLicense()
|
||||
{
|
||||
std::cout << "\
|
||||
moFileReader - A simple .mo-File-Reader\n\
|
||||
Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)\n\
|
||||
All rights reserved. \n\
|
||||
\n\
|
||||
Redistribution and use in source and binary forms, with or without\n\
|
||||
modification, are permitted provided that the following conditions\n\
|
||||
are met:\n\
|
||||
\n\
|
||||
1. Redistributions of source code must retain the above copyright\n\
|
||||
notice, this list of conditions and the following disclaimer.\n\
|
||||
2. Redistributions in binary form must reproduce the above copyright\n\
|
||||
notice, this list of conditions and the following disclaimer in the\n\
|
||||
documentation and/or other materials provided with the distribution.\n\
|
||||
\n\
|
||||
3. The names of its contributors may not be used to endorse or promote \n\
|
||||
products derived from this software without specific prior written \n\
|
||||
permission.\n\
|
||||
\n\
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\
|
||||
\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n\
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n\
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n\
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n\
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n\
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
|
||||
" << std::endl;
|
||||
std::cout << R"(
|
||||
moFileReader - A simple .mo-File-Reader
|
||||
Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
Copyright (C) 2018-2021 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. The names of its contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
)" << std::endl;
|
||||
}
|
||||
|
||||
std::string GetAppName(const char *raw)
|
||||
@ -100,8 +102,6 @@ std::string GetAppName(const char* raw)
|
||||
return r;
|
||||
}
|
||||
|
||||
#if defined(_CONSOLE)
|
||||
|
||||
int main(int, char **argv)
|
||||
{
|
||||
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||
@ -143,10 +143,7 @@ int main( int, char** argv )
|
||||
Usage(appname);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if ( argv[3] )
|
||||
{
|
||||
outfile = argv[3];
|
||||
}
|
||||
if (argv[3]) { outfile = argv[3]; }
|
||||
|
||||
moFileReader::eErrorCode r = moFileReader::ExportAsHTML(argv[2], outfile);
|
||||
if (r == moFileReader::EC_SUCCESS)
|
||||
@ -203,30 +200,3 @@ int main( int, char** argv )
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(_USRDLL) && defined(WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
extern "C"
|
||||
int WINAPI DllMain( DWORD reason, LPVOID)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
#if defined (_DEBUG) && defined(_MSC_VER)
|
||||
long flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
|
||||
flag |= _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF;
|
||||
_CrtSetDbgFlag(flag);
|
||||
#endif /* _MSC_VER && _DEBUG */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* Compilation-Mode */
|
||||
|
@ -1,526 +0,0 @@
|
||||
/*
|
||||
* moFileReader - A simple .mo-File-Reader
|
||||
* Copyright (C) 2009 Domenico Gentner (scorcher24@gmail.com)
|
||||
* Copyright (C) 2018 Edgar (Edgar@AnotherFoxGuy.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The names of its contributors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "moFileReader.h"
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
MO_BEGIN_NAMESPACE
|
||||
|
||||
unsigned long moFileReader::SwapBytes(unsigned long in)
|
||||
{
|
||||
unsigned long b0 = (in >> 0) & 0xff;
|
||||
unsigned long b1 = (in >> 8) & 0xff;
|
||||
unsigned long b2 = (in >> 16) & 0xff;
|
||||
unsigned long b3 = (in >> 24) & 0xff;
|
||||
|
||||
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
}
|
||||
|
||||
const std::string& moFileReader::GetErrorDescription() const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
void moFileReader::ClearTable()
|
||||
{
|
||||
m_lookup.clear();
|
||||
}
|
||||
|
||||
unsigned int moFileReader::GetNumStrings() const
|
||||
{
|
||||
return m_lookup.size();
|
||||
}
|
||||
|
||||
std::string moFileReader::Lookup( const char* id ) const
|
||||
{
|
||||
if ( m_lookup.size() <= 0) return id;
|
||||
moLookupList::const_iterator iterator = m_lookup.find(id);
|
||||
|
||||
if ( iterator == m_lookup.end() )
|
||||
{
|
||||
return id;
|
||||
}
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
std::string moFileReader::LookupWithContext (const char* context, const char* id) const
|
||||
{
|
||||
std::string idName = context;
|
||||
idName += '\x04';
|
||||
idName += id;
|
||||
|
||||
if (m_lookup.size () <= 0) return id;
|
||||
moLookupList::const_iterator iterator = m_lookup.find (idName);
|
||||
|
||||
if (iterator == m_lookup.end ())
|
||||
{
|
||||
return id;
|
||||
}
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
moFileReader::eErrorCode moFileReader::ParseData(std::string data)
|
||||
{
|
||||
// Creating a file-description.
|
||||
moFileInfo moInfo;
|
||||
|
||||
// Reference to the List inside moInfo.
|
||||
moFileInfo::moTranslationPairList& TransPairInfo = moInfo.m_translationPairInformation;
|
||||
|
||||
// Opening the file.
|
||||
std::stringstream stream(data);
|
||||
|
||||
// Read in all the 4 bytes of fire-magic, offsets and stuff...
|
||||
stream.read((char*)&moInfo.m_magicNumber, 4);
|
||||
stream.read((char*)&moInfo.m_fileVersion, 4);
|
||||
stream.read((char*)&moInfo.m_numStrings, 4);
|
||||
stream.read((char*)&moInfo.m_offsetOriginal, 4);
|
||||
stream.read((char*)&moInfo.m_offsetTranslation, 4);
|
||||
stream.read((char*)&moInfo.m_sizeHashtable, 4);
|
||||
stream.read((char*)&moInfo.m_offsetHashtable, 4);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Checking the Magic Number
|
||||
if ( MagicNumber != moInfo.m_magicNumber )
|
||||
{
|
||||
if ( MagicReversed != moInfo.m_magicNumber )
|
||||
{
|
||||
m_error = "The Magic Number does not match in all cases!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_MAGICNUMBER_NOMATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
moInfo.m_reversed = true;
|
||||
m_error = "Magic Number is reversed. We do not support this yet!";
|
||||
return moFileReader::EC_MAGICNUMBER_REVERSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we search all Length & Offsets of the original strings
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++ )
|
||||
{
|
||||
moTranslationPairInformation _str;
|
||||
stream.read((char*)&_str.m_orLength, 4);
|
||||
stream.read((char*)&_str.m_orOffset, 4);
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
TransPairInfo.push_back(_str);
|
||||
}
|
||||
|
||||
// Get all Lengths & Offsets of the translated strings
|
||||
// Be aware: The Descriptors already exist in our list, so we just mod. refs from the deque.
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++ )
|
||||
{
|
||||
moTranslationPairInformation& _str = TransPairInfo[i];
|
||||
stream.read((char*)&_str.m_trLength, 4);
|
||||
stream.read((char*)&_str.m_trOffset, 4);
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally you would read the hash-table here, but we don't use it. :)
|
||||
|
||||
// Now to the interesting part, we read the strings-pairs now
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
// We need a length of +1 to catch the trailing \0.
|
||||
int orLength = TransPairInfo[i].m_orLength+1;
|
||||
int trLength = TransPairInfo[i].m_trLength+1;
|
||||
|
||||
int orOffset = TransPairInfo[i].m_orOffset;
|
||||
int trOffset = TransPairInfo[i].m_trOffset;
|
||||
|
||||
// Original
|
||||
char* original = new char[orLength];
|
||||
memset(original, 0, sizeof(char)*orLength);
|
||||
|
||||
stream.seekg(orOffset);
|
||||
stream.read(original, orLength);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Translation
|
||||
char* translation = new char[trLength];
|
||||
memset(translation, 0, sizeof(char)*trLength);
|
||||
|
||||
stream.seekg(trOffset);
|
||||
stream.read(translation, trLength);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
printf("%s", m_error.c_str());
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Store it in the map.
|
||||
m_lookup[std::string(original)] = std::string(translation);
|
||||
|
||||
// Cleanup...
|
||||
delete original;
|
||||
delete translation;
|
||||
}
|
||||
|
||||
// Done :)
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
moFileReader::eErrorCode moFileReader::ReadFile( const char* filename )
|
||||
{
|
||||
// Creating a file-description.
|
||||
moFileInfo moInfo;
|
||||
|
||||
// Reference to the List inside moInfo.
|
||||
moFileInfo::moTranslationPairList& TransPairInfo = moInfo.m_translationPairInformation;
|
||||
|
||||
// Opening the file.
|
||||
std::ifstream stream( filename, std::ios_base::binary | std::ios_base::in );
|
||||
if ( !stream.is_open() )
|
||||
{
|
||||
m_error = std::string("Cannot open File ") + std::string(filename);
|
||||
return moFileReader::EC_FILENOTFOUND;
|
||||
}
|
||||
|
||||
// Read in all the 4 bytes of fire-magic, offsets and stuff...
|
||||
stream.read((char*)&moInfo.m_magicNumber, 4);
|
||||
stream.read((char*)&moInfo.m_fileVersion, 4);
|
||||
stream.read((char*)&moInfo.m_numStrings, 4);
|
||||
stream.read((char*)&moInfo.m_offsetOriginal, 4);
|
||||
stream.read((char*)&moInfo.m_offsetTranslation, 4);
|
||||
stream.read((char*)&moInfo.m_sizeHashtable, 4);
|
||||
stream.read((char*)&moInfo.m_offsetHashtable, 4);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Checking the Magic Number
|
||||
if ( MagicNumber != moInfo.m_magicNumber )
|
||||
{
|
||||
if ( MagicReversed != moInfo.m_magicNumber )
|
||||
{
|
||||
m_error = "The Magic Number does not match in all cases!";
|
||||
//return moFileReader::EC_MAGICNUMBER_NOMATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
moInfo.m_reversed = true;
|
||||
m_error = "Magic Number is reversed. We do not support this yet!";
|
||||
return moFileReader::EC_MAGICNUMBER_REVERSED;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we search all Length & Offsets of the original strings
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++ )
|
||||
{
|
||||
moTranslationPairInformation _str;
|
||||
stream.read((char*)&_str.m_orLength, 4);
|
||||
stream.read((char*)&_str.m_orOffset, 4);
|
||||
if ( stream.bad() )
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
TransPairInfo.push_back(_str);
|
||||
}
|
||||
|
||||
// Get all Lengths & Offsets of the translated strings
|
||||
// Be aware: The Descriptors already exist in our list, so we just mod. refs from the deque.
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++ )
|
||||
{
|
||||
moTranslationPairInformation& _str = TransPairInfo[i];
|
||||
stream.read((char*)&_str.m_trLength, 4);
|
||||
stream.read((char*)&_str.m_trOffset, 4);
|
||||
if ( stream.bad() )
|
||||
{
|
||||
stream.close();
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// Normally you would read the hash-table here, but we don't use it. :)
|
||||
|
||||
// Now to the interesting part, we read the strings-pairs now
|
||||
for ( int i = 0; i < moInfo.m_numStrings; i++)
|
||||
{
|
||||
// We need a length of +1 to catch the trailing \0.
|
||||
int orLength = TransPairInfo[i].m_orLength+1;
|
||||
int trLength = TransPairInfo[i].m_trLength+1;
|
||||
|
||||
int orOffset = TransPairInfo[i].m_orOffset;
|
||||
int trOffset = TransPairInfo[i].m_trOffset;
|
||||
|
||||
// Original
|
||||
char* original = new char[orLength];
|
||||
memset(original, 0, sizeof(char)*orLength);
|
||||
|
||||
stream.seekg(orOffset);
|
||||
stream.read(original, orLength);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Translation
|
||||
char* translation = new char[trLength];
|
||||
memset(translation, 0, sizeof(char)*trLength);
|
||||
|
||||
stream.seekg(trOffset);
|
||||
stream.read(translation, trLength);
|
||||
|
||||
if ( stream.bad() )
|
||||
{
|
||||
m_error = "Stream bad during reading. The .mo-file seems to be invalid or has bad descriptions!";
|
||||
return moFileReader::EC_FILEINVALID;
|
||||
}
|
||||
|
||||
// Store it in the map.
|
||||
m_lookup[std::string(original)] = std::string(translation);
|
||||
|
||||
// Cleanup...
|
||||
delete original;
|
||||
delete translation;
|
||||
}
|
||||
|
||||
// Done :)
|
||||
stream.close();
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
moFileReader::eErrorCode moFileReader::ExportAsHTML(std::string infile, std::string filename, std::string css )
|
||||
{
|
||||
// Read the file
|
||||
moFileReader reader;
|
||||
moFileReader::eErrorCode r = reader.ReadFile(infile.c_str()) ;
|
||||
if ( r != moFileReader::EC_SUCCESS )
|
||||
{
|
||||
return r;
|
||||
}
|
||||
if ( reader.m_lookup.empty() )
|
||||
{
|
||||
return moFileReader::EC_TABLEEMPTY;
|
||||
}
|
||||
|
||||
// Beautify Output
|
||||
std::string fname;
|
||||
unsigned int pos = infile.find_last_of(moPATHSEP);
|
||||
if ( pos != std::string::npos )
|
||||
{
|
||||
fname = infile.substr( pos+1, infile.length() );
|
||||
}
|
||||
else
|
||||
{
|
||||
fname = infile;
|
||||
}
|
||||
|
||||
// if there is no filename given, we set it to the .mo + html, e.g. test.mo.html
|
||||
std::string htmlfile(filename);
|
||||
if (htmlfile.empty())
|
||||
{
|
||||
htmlfile = infile + std::string(".html");
|
||||
}
|
||||
|
||||
// Ok, now prepare output.
|
||||
std::ofstream stream(htmlfile.c_str());
|
||||
if ( stream.is_open() )
|
||||
{
|
||||
stream << "<!DOCTYPE HTML PUBLIC \"- //W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" << std::endl;
|
||||
stream << "<html><head><style type=\"text/css\">\n" << std::endl;
|
||||
stream << css << std::endl;
|
||||
stream << "</style>" << std::endl;
|
||||
stream << "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">" << std::endl;
|
||||
stream << "<title>Dump of " << fname << "</title></head>" << std::endl;
|
||||
stream << "<body>" << std::endl;
|
||||
stream << "<center>" <<std::endl;
|
||||
stream << "<h1>" << fname << "</h1>" << std::endl;
|
||||
stream << "<table border=\"1\"><th colspan=\"2\">Project Info</th>" << std::endl;
|
||||
|
||||
std::stringstream parsee;
|
||||
parsee << reader.Lookup("");
|
||||
|
||||
while ( !parsee.eof() )
|
||||
{
|
||||
char buffer[1024];
|
||||
parsee.getline(buffer, 1024);
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
reader.GetPoEditorString( buffer, name, value );
|
||||
if ( !(name.empty() || value.empty()) )
|
||||
{
|
||||
stream << "<tr><td>" << name << "</td><td>" << value << "</td></tr>" << std::endl;
|
||||
}
|
||||
}
|
||||
stream << "</table>" << std::endl;
|
||||
stream << "<hr noshade/>" << std::endl;
|
||||
|
||||
// Now output the content
|
||||
stream << "<table border=\"1\"><th colspan=\"2\">Content</th>" << std::endl;
|
||||
for ( moLookupList::const_iterator it = reader.m_lookup.begin();
|
||||
it != reader.m_lookup.end(); it++)
|
||||
{
|
||||
if ( it->first != "" ) // Skip the empty msgid, its the table we handled above.
|
||||
{
|
||||
stream << "<tr><td>" << it->first << "</td><td>" << it->second << "</td></tr>" << std::endl;
|
||||
}
|
||||
}
|
||||
stream << "</table><br/>" << std::endl;
|
||||
|
||||
stream << "</center>" << std::endl;
|
||||
stream << "<div class=\"copyleft\">File generated by <a href=\"https://github.com/AnotherFoxGuy/MofileReader\" target=\"_blank\">moFileReaderSDK</a></div>" << std::endl;
|
||||
stream << "</body></html>" << std::endl;
|
||||
stream.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
return moFileReader::EC_FILENOTFOUND;
|
||||
}
|
||||
|
||||
return moFileReader::EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// Removes spaces from front and end.
|
||||
void moFileReader::Trim(std::string& in)
|
||||
{
|
||||
while ( in[0] == ' ' )
|
||||
{
|
||||
in = in.substr(1, in.length() );
|
||||
}
|
||||
while( in[in.length()] == ' ' )
|
||||
{
|
||||
in = in.substr(0, in.length() - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Extracts a value-pair from the po-edit-information
|
||||
bool moFileReader::GetPoEditorString(const char* buffer, std::string& name, std::string& value)
|
||||
{
|
||||
std::string line(buffer);
|
||||
size_t first = line.find_first_of(':');
|
||||
|
||||
if ( first != std::string::npos )
|
||||
{
|
||||
name = line.substr( 0, first );
|
||||
value = line.substr( first + 1, line.length() );
|
||||
|
||||
// Replace <> with () for Html-Conformity.
|
||||
MakeHtmlConform(value);
|
||||
MakeHtmlConform(name);
|
||||
|
||||
// Remove spaces from front and end.
|
||||
Trim(value);
|
||||
Trim(name);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replaces < with ( to satisfy html-rules.
|
||||
void moFileReader::MakeHtmlConform(std::string& inout)
|
||||
{
|
||||
std::string temp = inout;
|
||||
for ( unsigned int i = 0; i < temp.length(); i++)
|
||||
{
|
||||
if ( temp[i] == '>')
|
||||
{
|
||||
inout.replace(i, 1, ")");
|
||||
}
|
||||
if ( temp[i] == '<' )
|
||||
{
|
||||
inout.replace(i, 1, "(");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
moFileReaderSingleton& moFileReaderSingleton::GetInstance()
|
||||
{
|
||||
static moFileReaderSingleton theoneandonly;
|
||||
return theoneandonly;
|
||||
}
|
||||
|
||||
|
||||
moFileReaderSingleton::moFileReaderSingleton(const moFileReaderSingleton& )
|
||||
{
|
||||
}
|
||||
|
||||
moFileReaderSingleton::moFileReaderSingleton()
|
||||
{
|
||||
}
|
||||
|
||||
moFileReaderSingleton& moFileReaderSingleton::operator=(const moFileReaderSingleton&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MO_END_NAMESPACE
|
@ -1,17 +1,16 @@
|
||||
if(NOT EXISTS "${CMAKE_BINARY_DIR}/catch/catch.hpp")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/catch")
|
||||
message(STATUS "Downloading catch.hpp from https://github.com/catchorg/Catch2/")
|
||||
file(DOWNLOAD "https://github.com/catchorg/Catch2/releases/download/v2.5.0/catch.hpp"
|
||||
"${CMAKE_BINARY_DIR}/catch/catch.hpp")
|
||||
endif()
|
||||
project(moFileReaderTest)
|
||||
find_package(Catch2 REQUIRED)
|
||||
|
||||
add_executable(moFileReaderTest test.cpp)
|
||||
target_include_directories(moFileReaderTest PRIVATE ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/catch)
|
||||
target_link_libraries(moFileReaderTest moFileReader)
|
||||
add_test(NAME mo_test COMMAND moFileReaderTest)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
|
||||
add_executable(${PROJECT_NAME} test.cpp link_test.cpp)
|
||||
target_include_directories(moFileReaderTest PRIVATE ${CMAKE_SOURCE_DIR}/include)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Catch2::Catch2)
|
||||
catch_discover_tests(${PROJECT_NAME})
|
||||
|
||||
add_custom_command(
|
||||
TARGET moFileReaderTest POST_BUILD
|
||||
TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/test.mo $<TARGET_FILE_DIR:moFileReaderTest>/test.mo
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/test.mo ${CMAKE_CURRENT_BINARY_DIR}/test.mo
|
||||
)
|
||||
|
17
test/link_test.cpp
Normal file
17
test/link_test.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "catch.hpp"
|
||||
#include "moFileReader.hpp"
|
||||
|
||||
using namespace moFileLib;
|
||||
#define _L(str) moFileReaderSingleton::GetInstance().Lookup(str)
|
||||
#define _LC(ctx, str) moFileReaderSingleton::GetInstance().LookupWithContext(ctx, str)
|
||||
|
||||
void test()
|
||||
{
|
||||
moFileReaderSingleton::GetInstance().ReadFile("test.mo");
|
||||
/* This is the first comment. */
|
||||
CHECK("Text Nederlands Een" == _L("String English One"));
|
||||
/* This is the second comment. */
|
||||
CHECK("Text Nederlands Twee" == _L("String English Two"));
|
||||
/* This is the third comment. */
|
||||
CHECK("Text Nederlands Drie" == _L("String English Three"));
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "moFileReader.h"
|
||||
#include "catch.hpp"
|
||||
#include "moFileReader.hpp"
|
||||
|
||||
using namespace moFileLib;
|
||||
#define _L(str) moFileReaderSingleton::GetInstance().Lookup(str)
|
||||
@ -23,7 +23,6 @@ TEST_CASE ("Lookup string", "[Lookup]")
|
||||
CHECK("Text Nederlands Drie" == _L("String English Three"));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Lookup string with context", "[LookupWithContext]")
|
||||
{
|
||||
moFileReaderSingleton::GetInstance().ReadFile("test.mo");
|
||||
|
@ -1,31 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "- //W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html><head><style type="text/css">
|
||||
|
||||
body { background-color: black; color: silver;}table {width: 80%;}th {background-color: orange;color: black;}hr { color: red;width: 80%; size: 5px; }a:link{color: gold;}a:visited{color: grey;}a:hover{color:blue;}.copyleft{ font-size: 12px; text-align: center;}
|
||||
</style>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Dump of test.mo</title></head>
|
||||
<body>
|
||||
<center>
|
||||
<h1>test.mo</h1>
|
||||
<table border="1"><th colspan="2">Project Info</th>
|
||||
<tr><td>Project-Id-Version</td><td>moFileTest</td></tr>
|
||||
<tr><td>POT-Creation-Date</td><td>2012-05-20 00:51+0100</td></tr>
|
||||
<tr><td>PO-Revision-Date</td><td>2012-05-20 00:57+0100</td></tr>
|
||||
<tr><td>Last-Translator</td><td>scorcher24 <scorcher24@gmail.>om></td></tr>
|
||||
<tr><td>MIME-Version</td><td>1.0</td></tr>
|
||||
<tr><td>Content-Type</td><td>text/plain; charset=UTF-8</td></tr>
|
||||
<tr><td>Content-Transfer-Encoding</td><td>8bit</td></tr>
|
||||
<tr><td>X-Poedit-KeywordsList</td><td>_;gettext;gettext_noop</td></tr>
|
||||
<tr><td>X-Poedit-Basepath</td><td>.</td></tr>
|
||||
<tr><td>X-Poedit-SearchPath-0</td><td>.</td></tr>
|
||||
</table>
|
||||
<hr noshade/>
|
||||
<table border="1"><th colspan="2">Content</th>
|
||||
<tr><td>String English One</td><td>Zeichenkette Englisch Eins</td></tr>
|
||||
<tr><td>String English Three</td><td>Zeichenkette Englisch Drei</td></tr>
|
||||
<tr><td>String English Two</td><td>Zeichenkette Englisch Zwei</td></tr>
|
||||
</table><br/>
|
||||
</center>
|
||||
<div class="copyleft">File generated by <a href="https://github.com/AnotherFoxGuy/MofileReader" target="_blank">moFileReaderSDK</a></div>
|
||||
</body></html>
|
Loading…
x
Reference in New Issue
Block a user