[
  {
    "path": ".gitignore",
    "content": "*.ipch\r\nBrowse.VC.db\r\nBrowse.VC.opendb\r\n.suo\r\n_Build/*\r\nBin/*\r\n.vs/*\r\n*.user\r\nFbxFormatConverter.vcxproj.user"
  },
  {
    "path": "FbxFormatConverter.args.json",
    "content": "{\r\n  \"FileVersion\": 2,\r\n  \"Id\": \"9e46203a-785a-41a3-bd18-2de2a7a7e4d7\",\r\n  \"Items\": [\r\n    {\r\n      \"Id\": \"048f9f3d-b4f7-421a-88a2-8208d935e75d\",\r\n      \"Command\": \"\",\r\n      \"Items\": [\r\n        {\r\n          \"Id\": \"02d89d7e-4960-4457-bcb6-3425ba20ab07\",\r\n          \"Command\": \"-q blah.fbx\"\r\n        },\r\n        {\r\n          \"Id\": \"28299385-031f-4af4-91dd-1c590319b3ef\",\r\n          \"Command\": \"-q SK_Chr_Attach_Female_Armor_02.fbx\"\r\n        },\r\n        {\r\n          \"Id\": \"c55eea3c-9a11-4ef5-b3c6-dbf81f43e261\",\r\n          \"Command\": \"-q TestData\"\r\n        }\r\n      ]\r\n    },\r\n    {\r\n      \"Id\": \"5fa48bfb-6393-481a-b2ab-c0bd71ed50f1\",\r\n      \"Command\": \"\",\r\n      \"Items\": [\r\n        {\r\n          \"Id\": \"5ae255c1-876e-4bcd-b400-edd0be3b171f\",\r\n          \"Command\": \"-c SM_Bld_Apartment_01.fbx\"\r\n        },\r\n        {\r\n          \"Id\": \"778e8d89-1616-468a-a9b1-623270e645a3\",\r\n          \"Command\": \"-o TestFileOut.fbx\"\r\n        },\r\n        {\r\n          \"Id\": \"12a719b6-1313-4bc5-802f-5255a8f72766\",\r\n          \"Command\": \"-binary\"\r\n        },\r\n        {\r\n          \"Id\": \"d8f98b79-6ee4-4bf0-bc49-bf92c8666b44\",\r\n          \"Command\": \"-ascii\"\r\n        }\r\n      ]\r\n    },\r\n    {\r\n      \"Id\": \"3f90e0f3-43db-4bbe-9976-f82862fc5ebb\",\r\n      \"Command\": \"\",\r\n      \"Items\": [\r\n        {\r\n          \"Id\": \"5a09faa8-7239-44a1-bd45-ab3d7e42064b\",\r\n          \"Command\": \"-c TestData\"\r\n        },\r\n        {\r\n          \"Id\": \"730b2ceb-ba4c-4251-9406-2251cb22ba37\",\r\n          \"Command\": \"-o Converted.fbx\"\r\n        },\r\n        {\r\n          \"Id\": \"289c0524-0c30-4d5a-8195-359af124689c\",\r\n          \"Command\": \"-ascii\"\r\n        }\r\n      ]\r\n    }\r\n  ]\r\n}"
  },
  {
    "path": "FbxFormatConverter.props",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ImportGroup Label=\"PropertySheets\" />\r\n  <PropertyGroup Label=\"UserMacros\">\r\n    <FBX_SDK_DIR>C:\\Program Files\\Autodesk\\FBX\\FBX SDK\\2020.0.1\\</FBX_SDK_DIR>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <ItemDefinitionGroup>\r\n    <ClCompile>\r\n      <AdditionalIncludeDirectories>$(FBX_SDK_DIR)include\\;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalLibraryDirectories Condition=\"$(Configuration) == 'Debug'\">$(FBX_SDK_DIR)lib\\vs2017\\x64\\debug\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <AdditionalLibraryDirectories Condition=\"$(Configuration) == 'Release'\">$(FBX_SDK_DIR)lib\\vs2017\\x64\\release\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <AdditionalDependencies>libfbxsdk-mt.lib;zlib-mt.lib;libxml2-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n</Project>"
  },
  {
    "path": "FbxFormatConverter.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.29905.134\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"FbxFormatConverter\", \"FbxFormatConverter.vcxproj\", \"{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|x64 = Debug|x64\r\n\t\tRelease|x64 = Release|x64\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}.Debug|x64.ActiveCfg = Debug|x64\r\n\t\t{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}.Debug|x64.Build.0 = Debug|x64\r\n\t\t{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}.Release|x64.ActiveCfg = Release|x64\r\n\t\t{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}.Release|x64.Build.0 = Release|x64\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\n\tGlobalSection(ExtensibilityGlobals) = postSolution\r\n\t\tSolutionGuid = {DAC409EE-F3F3-4A2C-B22F-316A9B8CAEFA}\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "FbxFormatConverter.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <VCProjectVersion>16.0</VCProjectVersion>\r\n    <ProjectGuid>{9E46203A-785A-41A3-BD18-2DE2A7A7E4D7}</ProjectGuid>\r\n    <RootNamespace>FbxFormatConverter</RootNamespace>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>true</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <UseDebugLibraries>false</UseDebugLibraries>\r\n    <PlatformToolset>v142</PlatformToolset>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"Shared\">\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"FbxFormatConverter.props\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"FbxFormatConverter.props\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"FbxFormatConverter.props\" />\r\n  </ImportGroup>\r\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n    <Import Project=\"FbxFormatConverter.props\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <IntDir>_Build\\$(Platform)_$(Configuration)\\</IntDir>\r\n    <OutDir>$(SolutionDir)Bin\\$(Platform)_$(Configuration)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <OutDir>$(SolutionDir)Bin\\$(Platform)_$(Configuration)\\</OutDir>\r\n    <IntDir>_Build\\$(Platform)_$(Configuration)\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level3</WarningLevel>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <FunctionLevelLinking>true</FunctionLevelLinking>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <SDLCheck>true</SDLCheck>\r\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <ConformanceMode>true</ConformanceMode>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <TreatWarningAsError>true</TreatWarningAsError>\r\n    </ClCompile>\r\n    <Link>\r\n      <SubSystem>Console</SubSystem>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n    </Link>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"main.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"cmdParser.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"FbxFormatConverter.props\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "FbxFormatConverter.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <ClCompile Include=\"main.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"cmdParser.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"FbxFormatConverter.props\" />\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Bobby Anguelov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "cmdParser.h",
    "content": "/*\r\nThis file is part of the C++ CmdParser utility.\r\nCopyright (c) 2015 - 2016 Florian Rappl\r\n*/\r\n\r\n#pragma once\r\n#include <iostream>\r\n#include <stdexcept>\r\n#include <string>\r\n#include <vector>\r\n#include <sstream>\r\n#include <functional>\r\n\r\nnamespace cli {\r\n    struct CallbackArgs {\r\n        const std::vector<std::string>& arguments;\r\n        std::ostream& output;\r\n        std::ostream& error;\r\n    };\r\n    class Parser {\r\n    private:\r\n        class CmdBase {\r\n        public:\r\n            explicit CmdBase( const std::string& name, const std::string& alternative, const std::string& description, bool required, bool dominant, bool variadic ) :\r\n                name( name ),\r\n                command( name.size() > 0 ? \"-\" + name : \"\" ),\r\n                alternative( alternative.size() > 0 ? \"--\" + alternative : \"\" ),\r\n                description( description ),\r\n                required( required ),\r\n                handled( false ),\r\n                arguments( {} ),\r\n                dominant( dominant ),\r\n                variadic( variadic ) {\r\n            }\r\n\r\n            virtual ~CmdBase() {\r\n            }\r\n\r\n            std::string name;\r\n            std::string command;\r\n            std::string alternative;\r\n            std::string description;\r\n            bool required;\r\n            bool handled;\r\n            std::vector<std::string> arguments;\r\n            bool const dominant;\r\n            bool const variadic;\r\n\r\n            virtual std::string print_value() const = 0;\r\n            virtual bool parse( std::ostream& output, std::ostream& error ) = 0;\r\n\r\n            bool is( const std::string& given ) const {\r\n                return given == command || given == alternative;\r\n            }\r\n        };\r\n\r\n        template<typename T>\r\n        struct ArgumentCountChecker\r\n        {\r\n            static constexpr bool Variadic = false;\r\n        };\r\n\r\n        template<typename T>\r\n        struct ArgumentCountChecker<std::vector<T>>\r\n        {\r\n            static constexpr bool Variadic = true;\r\n        };\r\n\r\n        template<typename T>\r\n        class CmdFunction final : public CmdBase {\r\n        public:\r\n            explicit CmdFunction( const std::string& name, const std::string& alternative, const std::string& description, bool required, bool dominant ) :\r\n                CmdBase( name, alternative, description, required, dominant, ArgumentCountChecker<T>::Variadic ) {\r\n            }\r\n\r\n            virtual bool parse( std::ostream& output, std::ostream& error ) {\r\n                try\r\n                {\r\n                    CallbackArgs args{ arguments, output, error };\r\n                    value = callback( args );\r\n                    return true;\r\n                }\r\n                catch ( ... )\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            virtual std::string print_value() const {\r\n                return \"\";\r\n            }\r\n\r\n            std::function<T( CallbackArgs& )> callback;\r\n            T value;\r\n        };\r\n\r\n        template<typename T>\r\n        class CmdArgument final : public CmdBase {\r\n        public:\r\n            explicit CmdArgument( const std::string& name, const std::string& alternative, const std::string& description, bool required, bool dominant ) :\r\n                CmdBase( name, alternative, description, required, dominant, ArgumentCountChecker<T>::Variadic ) {\r\n            }\r\n\r\n            virtual bool parse( std::ostream&, std::ostream& ) {\r\n                try\r\n                {\r\n                    value = Parser::parse( arguments, value );\r\n                    return true;\r\n                }\r\n                catch ( ... )\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            virtual std::string print_value() const {\r\n                return stringify( value );\r\n            }\r\n\r\n            T value;\r\n        };\r\n\r\n        static int parse( const std::vector<std::string>& elements, const int& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stoi( elements[0] );\r\n        }\r\n\r\n        static bool parse( const std::vector<std::string>& elements, const bool& defval ) {\r\n            if ( elements.size() != 0 )\r\n                throw std::runtime_error( \"A boolean command line parameter cannot have any arguments.\" );\r\n\r\n            return !defval;\r\n        }\r\n\r\n        static double parse( const std::vector<std::string>& elements, const double& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stod( elements[0] );\r\n        }\r\n\r\n        static float parse( const std::vector<std::string>& elements, const float& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stof( elements[0] );\r\n        }\r\n\r\n        static long double parse( const std::vector<std::string>& elements, const long double& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stold( elements[0] );\r\n        }\r\n\r\n        static unsigned int parse( const std::vector<std::string>& elements, const unsigned int& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return static_cast<unsigned int>( std::stoul( elements[0] ) );\r\n        }\r\n\r\n        static unsigned long parse( const std::vector<std::string>& elements, const unsigned long& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stoul( elements[0] );\r\n        }\r\n\r\n        static long parse( const std::vector<std::string>& elements, const long& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return std::stol( elements[0] );\r\n        }\r\n\r\n        static std::string parse( const std::vector<std::string>& elements, const std::string& ) {\r\n            //if ( elements.size() != 1 )\r\n            //    throw std::bad_cast();\r\n\r\n            return elements[0];\r\n        }\r\n\r\n        template<class T>\r\n        static std::vector<T> parse( const std::vector<std::string>& elements, const std::vector<T>& ) {\r\n            const T defval = T();\r\n            std::vector<T> values{};\r\n            std::vector<std::string> buffer( 1 );\r\n\r\n            for ( const auto& element : elements )\r\n            {\r\n                buffer[0] = element;\r\n                values.push_back( parse( buffer, defval ) );\r\n            }\r\n\r\n            return values;\r\n        }\r\n\r\n        template<class T>\r\n        static std::string stringify( const T& value ) {\r\n            return std::to_string( value );\r\n        }\r\n\r\n        template<class T>\r\n        static std::string stringify( const std::vector<T>& values ) {\r\n            std::stringstream ss{};\r\n            ss << \"[ \";\r\n\r\n            for ( const auto& value : values )\r\n            {\r\n                ss << stringify( value ) << \" \";\r\n            }\r\n\r\n            ss << \"]\";\r\n            return ss.str();\r\n        }\r\n\r\n        static std::string stringify( const std::string& str ) {\r\n            return str;\r\n        }\r\n\r\n    public:\r\n        explicit Parser( int argc, const char** argv ) :\r\n            _appname( argv[0] ) {\r\n            for ( int i = 1; i < argc; ++i )\r\n            {\r\n                _arguments.push_back( argv[i] );\r\n            }\r\n            enable_help();\r\n        }\r\n\r\n        explicit Parser( int argc, char** argv ) :\r\n            _appname( argv[0] ) {\r\n            for ( int i = 1; i < argc; ++i )\r\n            {\r\n                _arguments.push_back( argv[i] );\r\n            }\r\n            enable_help();\r\n        }\r\n\r\n        ~Parser() {\r\n            for ( int i = 0, n = _commands.size(); i < n; ++i )\r\n            {\r\n                delete _commands[i];\r\n            }\r\n        }\r\n\r\n        bool has_help() const {\r\n            for ( const auto command : _commands )\r\n            {\r\n                if ( command->name == \"h\" && command->alternative == \"--help\" )\r\n                {\r\n                    return true;\r\n                }\r\n            }\r\n\r\n            return false;\r\n        }\r\n\r\n        void enable_help() {\r\n            set_callback( \"h\", \"help\", std::function<bool( CallbackArgs& )>( [this] ( CallbackArgs& args ) {\r\n                args.output << this->usage();\r\n                exit( 0 );\r\n                return false;\r\n            } ), \"\", true );\r\n        }\r\n\r\n        void disable_help() {\r\n            for ( auto command = _commands.begin(); command != _commands.end(); ++command )\r\n            {\r\n                if ( ( *command )->name == \"h\" && ( *command )->alternative == \"--help\" )\r\n                {\r\n                    _commands.erase( command );\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        template<typename T>\r\n        void set_default( bool is_required, const std::string& description = \"\" ) {\r\n            auto command = new CmdArgument<T>{ \"\", \"\", description, is_required, false };\r\n            _commands.push_back( command );\r\n        }\r\n\r\n        template<typename T>\r\n        void set_required( const std::string& name, const std::string& alternative, const std::string& description = \"\", bool dominant = false ) {\r\n            auto command = new CmdArgument<T>{ name, alternative, description, true, dominant };\r\n            _commands.push_back( command );\r\n        }\r\n\r\n        template<typename T>\r\n        void set_optional( const std::string& name, const std::string& alternative, T defaultValue, const std::string& description = \"\", bool dominant = false ) {\r\n            auto command = new CmdArgument<T>{ name, alternative, description, false, dominant };\r\n            command->value = defaultValue;\r\n            _commands.push_back( command );\r\n        }\r\n\r\n        template<typename T>\r\n        void set_callback( const std::string& name, const std::string& alternative, std::function<T( CallbackArgs& )> callback, const std::string& description = \"\", bool dominant = false ) {\r\n            auto command = new CmdFunction<T>{ name, alternative, description, false, dominant };\r\n            command->callback = callback;\r\n            _commands.push_back( command );\r\n        }\r\n\r\n        inline void run_and_exit_if_error() {\r\n            if ( run() == false )\r\n            {\r\n                exit( 1 );\r\n            }\r\n        }\r\n\r\n        inline bool run() {\r\n            return run( std::cout, std::cerr );\r\n        }\r\n\r\n        inline bool run( std::ostream& output ) {\r\n            return run( output, std::cerr );\r\n        }\r\n\r\n        bool run( std::ostream& output, std::ostream& error ) {\r\n            if ( _arguments.size() > 0 )\r\n            {\r\n                auto current = find_default();\r\n\r\n                for ( int i = 0, n = _arguments.size(); i < n; ++i )\r\n                {\r\n                    auto isarg = _arguments[i].size() > 0 && _arguments[i][0] == '-';\r\n                    auto associated = isarg ? find( _arguments[i] ) : nullptr;\r\n\r\n                    if ( associated != nullptr )\r\n                    {\r\n                        current = associated;\r\n                        associated->handled = true;\r\n                    }\r\n                    else if ( current == nullptr )\r\n                    {\r\n                        //error << no_default();\r\n                        return false;\r\n                    }\r\n                    else\r\n                    {\r\n                        current->arguments.push_back( _arguments[i] );\r\n                        current->handled = true;\r\n                        if ( !current->variadic )\r\n                        {\r\n                            // If the current command is not variadic, then no more arguments\r\n                            // should be added to it. In this case, switch back to the default\r\n                            // command.\r\n                            current = find_default();\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            // First, parse dominant arguments since they succeed even if required\r\n            // arguments are missing.\r\n            for ( auto command : _commands )\r\n            {\r\n                if ( command->handled && command->dominant && !command->parse( output, error ) )\r\n                {\r\n                    error << howto_use( command );\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            // Next, check for any missing arguments.\r\n            for ( auto command : _commands )\r\n            {\r\n                if ( command->required && !command->handled )\r\n                {\r\n                    error << howto_required( command );\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            // Finally, parse all remaining arguments.\r\n            for ( auto command : _commands )\r\n            {\r\n                if ( command->handled && !command->dominant && !command->parse( output, error ) )\r\n                {\r\n                    error << howto_use( command );\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            return true;\r\n        }\r\n\r\n        template<typename T>\r\n        T get( const std::string& name ) const {\r\n            for ( const auto& command : _commands )\r\n            {\r\n                if ( command->name == name )\r\n                {\r\n                    auto cmd = dynamic_cast<CmdArgument<T>*>( command );\r\n\r\n                    if ( cmd == nullptr )\r\n                    {\r\n                        throw std::runtime_error( \"Invalid usage of the parameter \" + name + \" detected.\" );\r\n                    }\r\n\r\n                    return cmd->value;\r\n                }\r\n            }\r\n\r\n            throw std::runtime_error( \"The parameter \" + name + \" could not be found.\" );\r\n        }\r\n\r\n        template<typename T>\r\n        T get_if( const std::string& name, std::function<T( T )> callback ) const {\r\n            auto value = get<T>( name );\r\n            return callback( value );\r\n        }\r\n\r\n        int requirements() const {\r\n            int count = 0;\r\n\r\n            for ( const auto& command : _commands )\r\n            {\r\n                if ( command->required )\r\n                {\r\n                    ++count;\r\n                }\r\n            }\r\n\r\n            return count;\r\n        }\r\n\r\n        int commands() const {\r\n            return static_cast<int>( _commands.size() );\r\n        }\r\n\r\n        inline const std::string& app_name() const {\r\n            return _appname;\r\n        }\r\n\r\n    protected:\r\n        CmdBase* find( const std::string& name ) {\r\n            for ( auto command : _commands )\r\n            {\r\n                if ( command->is( name ) )\r\n                {\r\n                    return command;\r\n                }\r\n            }\r\n\r\n            return nullptr;\r\n        }\r\n\r\n        CmdBase* find_default() {\r\n            for ( auto command : _commands )\r\n            {\r\n                if ( command->name == \"\" )\r\n                {\r\n                    return command;\r\n                }\r\n            }\r\n\r\n            return nullptr;\r\n        }\r\n\r\n        std::string usage() const {\r\n            std::stringstream ss{};\r\n            ss << \"Available parameters:\\n\\n\";\r\n\r\n            for ( const auto& command : _commands )\r\n            {\r\n                ss << \"  \" << command->command << \"\\t\" << command->alternative;\r\n\r\n                if ( command->required == true )\r\n                {\r\n                    ss << \"\\t(required)\";\r\n                }\r\n\r\n                ss << \"\\n   \" << command->description;\r\n\r\n                if ( command->required == false )\r\n                {\r\n                    ss << \"\\n   \" << \"This parameter is optional. The default value is '\" + command->print_value() << \"'.\";\r\n                }\r\n\r\n                ss << \"\\n\\n\";\r\n            }\r\n\r\n            return ss.str();\r\n        }\r\n\r\n        void print_help( std::stringstream& ss ) const {\r\n            if ( has_help() )\r\n            {\r\n                ss << \"For more help use --help or -h.\\n\";\r\n            }\r\n        }\r\n\r\n        std::string howto_required( CmdBase* command ) const {\r\n            std::stringstream ss{};\r\n            ss << \"The parameter \" << command->name << \" is required.\\n\";\r\n            ss << command->description << '\\n';\r\n            print_help( ss );\r\n            return ss.str();\r\n        }\r\n\r\n        std::string howto_use( CmdBase* command ) const {\r\n            std::stringstream ss{};\r\n            ss << \"The parameter \" << command->name << \" has invalid arguments.\\n\";\r\n            ss << command->description << '\\n';\r\n            print_help( ss );\r\n            return ss.str();\r\n        }\r\n\r\n        std::string no_default() const {\r\n            std::stringstream ss{};\r\n            ss << \"No default parameter has been specified.\\n\";\r\n            ss << \"The given argument must be used with a parameter.\\n\";\r\n            print_help( ss );\r\n            return ss.str();\r\n        }\r\n\r\n    private:\r\n        const std::string _appname;\r\n        std::vector<std::string> _arguments;\r\n        std::vector<CmdBase*> _commands;\r\n    };\r\n}"
  },
  {
    "path": "main.cpp",
    "content": "#include <fbxsdk.h>\r\n#include <windows.h>\r\n#include <shlwapi.h>\r\n#include <shlobj.h>\r\n#include <shellapi.h>\r\n#include <assert.h>\r\n#include <functional>\r\n#include <algorithm>\r\n\r\n#if _MSC_VER\r\n#pragma warning(push, 0)\r\n#pragma warning(disable: 4702)\r\n#endif\r\n\r\n// Note: this has been modified for this application\r\n#include \"cmdParser.h\"\r\n\r\n#if _MSC_VER\r\n#pragma warning(pop)\r\n#endif\r\n\r\n//-------------------------------------------------------------------------\r\n\r\nenum class FileFormat\r\n{\r\n    Unknown,\r\n    Binary,\r\n    Ascii\r\n};\r\n\r\n//-------------------------------------------------------------------------\r\n\r\nnamespace FileSystemHelpers\r\n{\r\n    static std::string GetFullPathString( char const* pPath )\r\n    {\r\n        assert( pPath != nullptr && pPath[0] != 0 );\r\n\r\n        char fullpath[256] = { 0 };\r\n        DWORD length = GetFullPathNameA( pPath, 256, fullpath, nullptr );\r\n        assert( length != 0 && length != 255 );\r\n\r\n        // We always append the trailing slash to simplify further operations\r\n        DWORD const result = GetFileAttributesA( fullpath );\r\n        if ( result != INVALID_FILE_ATTRIBUTES && ( result & FILE_ATTRIBUTE_DIRECTORY ) && fullpath[length - 1] != '\\\\' )\r\n        {\r\n            fullpath[length] = '\\\\';\r\n            fullpath[length + 1] = 0;\r\n        }\r\n\r\n        return std::string( fullpath );\r\n    }\r\n\r\n    static std::string GetFullPathString( std::string const& path )\r\n    {\r\n        return GetFullPathString( path.c_str() );\r\n    }\r\n\r\n    static std::string GetParentDirectoryPath( std::string const& path )\r\n    {\r\n        std::string dirPath;\r\n        size_t const lastSlashIdx = path.rfind( '\\\\' );\r\n        if ( lastSlashIdx != std::string::npos )\r\n        {\r\n            dirPath = path.substr( 0, lastSlashIdx + 1 );\r\n        }\r\n\r\n        return dirPath;\r\n    }\r\n\r\n    static bool IsValidDirectoryPath( std::string const& directoryPath )\r\n    {\r\n        DWORD const result = GetFileAttributesA( directoryPath.c_str() );\r\n        if ( result != INVALID_FILE_ATTRIBUTES && ( result & FILE_ATTRIBUTE_DIRECTORY ) )\r\n        {\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    static FileFormat GetFileFormat( std::string const& filePath )\r\n    {\r\n        FileFormat fileFormat = FileFormat::Unknown;\r\n\r\n        FILE* fp = nullptr;\r\n        int errcode = fopen_s( &fp, filePath.c_str(), \"r\" );\r\n        if ( errcode != 0 )\r\n        {\r\n            return fileFormat;\r\n        }\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        fseek( fp, 0, SEEK_END );\r\n        size_t filesize = (size_t) ftell( fp );\r\n        fseek( fp, 0, SEEK_SET );\r\n\r\n        void* pFileData = malloc( filesize );\r\n        size_t readLength = fread( pFileData, 1, filesize, fp );\r\n        fclose( fp );\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        // Ascii files cannot contain the null character\r\n        if ( memchr( pFileData, '\\0', readLength ) != NULL )\r\n        {\r\n            fileFormat = FileFormat::Binary;\r\n        }\r\n        else\r\n        {\r\n            fileFormat = FileFormat::Ascii;\r\n        }\r\n\r\n        return fileFormat;\r\n    }\r\n\r\n    static void GetDirectoryContents( std::string const& directoryPath, std::vector<std::string>& directoryContents )\r\n    {\r\n        if ( !IsValidDirectoryPath( directoryPath ) )\r\n        {\r\n            printf( \"Error! %s is not a valid directory!\", directoryPath.c_str() );\r\n            return;\r\n        }\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        std::string const directorySearchPath = directoryPath + \"*\";\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        WIN32_FIND_DATAA findData;\r\n        HANDLE foundFileHandle = FindFirstFileA( directorySearchPath.c_str(), &findData );\r\n        assert( foundFileHandle != INVALID_HANDLE_VALUE );\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        char stringBuffer[1024] = { 0 };\r\n\r\n        do\r\n        {\r\n            if ( strcmp( findData.cFileName, \".\" ) == 0 || strcmp( findData.cFileName, \"..\" ) == 0 )\r\n            {\r\n                continue;\r\n            }\r\n\r\n            if ( findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )\r\n            {\r\n                sprintf_s( stringBuffer, 1024, \"%s%s\\\\\", directoryPath.c_str(), findData.cFileName );\r\n                GetDirectoryContents( stringBuffer, directoryContents );\r\n            }\r\n            else\r\n            {\r\n                sprintf_s( stringBuffer, 1024, \"%s%s\", directoryPath.c_str(), findData.cFileName );\r\n                directoryContents.emplace_back( GetFullPathString( stringBuffer ) );\r\n            }\r\n        } while ( FindNextFileA( foundFileHandle, &findData ) != 0 );\r\n    }\r\n\r\n    static bool MakeDir( char const* pDirectoryPath )\r\n    {\r\n        assert( pDirectoryPath != nullptr );\r\n        return SUCCEEDED( SHCreateDirectoryExA( nullptr, pDirectoryPath, nullptr ) );\r\n    }\r\n}\r\n\r\n//-------------------------------------------------------------------------\r\n\r\nclass FbxConverter\r\n{\r\npublic:\r\n\r\n    FbxConverter()\r\n        : m_pManager( FbxManager::Create() )\r\n    {\r\n        assert( m_pManager != nullptr );\r\n        auto pIOPluginRegistry = m_pManager->GetIOPluginRegistry();\r\n\r\n        // Find the IDs for the ascii and binary writers\r\n        int const numWriters = pIOPluginRegistry->GetWriterFormatCount();\r\n        for ( int i = 0; i < numWriters; i++ )\r\n        {\r\n            if ( pIOPluginRegistry->WriterIsFBX( i ) )\r\n            {\r\n                char const* pDescription = pIOPluginRegistry->GetWriterFormatDescription( i );\r\n                if ( strcmp( pDescription, \"FBX binary (*.fbx)\" ) == 0 )\r\n                {\r\n                    const_cast<int&>( m_binaryWriteID ) = i;\r\n                }\r\n                else if ( strcmp( pDescription, \"FBX ascii (*.fbx)\" ) == 0 )\r\n                {\r\n                    const_cast<int&>( m_asciiWriterID ) = i;\r\n                }\r\n            }\r\n        }\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        // This should never occur but I'm leaving it here in case someone updates the plugin with a new SDK and names change\r\n        assert( m_binaryWriteID != -1 && m_asciiWriterID != -1 );\r\n    }\r\n\r\n    ~FbxConverter()\r\n    {\r\n        m_pManager->Destroy();\r\n        m_pManager = nullptr;\r\n    }\r\n\r\n    int ConvertFbxFile( std::string const& inputFilepath, std::string const& outputFilepath, FileFormat outputFormat )\r\n    {\r\n        // Import\r\n        //-------------------------------------------------------------------------\r\n\r\n        FbxImporter* pImporter = FbxImporter::Create( m_pManager, \"FBX Importer\" );\r\n        if ( !pImporter->Initialize( inputFilepath.c_str(), -1, m_pManager->GetIOSettings() ) )\r\n        {\r\n            printf( \"Error! Failed to load specified FBX file ( %s ): %s\\n\\n\", inputFilepath.c_str(), pImporter->GetStatus().GetErrorString() );\r\n            return 1;\r\n        }\r\n\r\n        auto pScene = FbxScene::Create( m_pManager, \"ImportScene\" );\r\n        if ( !pImporter->Import( pScene ) )\r\n        {\r\n            printf( \"Error! Failed to import scene from file ( %s ): %s\\n\\n\", inputFilepath.c_str(), pImporter->GetStatus().GetErrorString() );\r\n            pImporter->Destroy();\r\n            return 1;\r\n        }\r\n        pImporter->Destroy();\r\n\r\n        // Set output format\r\n        //-------------------------------------------------------------------------\r\n\r\n        int const fileFormatIDToUse = ( outputFormat == FileFormat::Binary ) ? m_binaryWriteID : m_asciiWriterID;\r\n\r\n        // Export\r\n        //-------------------------------------------------------------------------\r\n\r\n        std::string const parentDirPath = FileSystemHelpers::GetParentDirectoryPath( outputFilepath );\r\n        if ( !FileSystemHelpers::MakeDir( parentDirPath.c_str() ) )\r\n        {\r\n            printf( \"Error! Failed to create output directory (%s)!\\n\\n\", outputFilepath.c_str() );\r\n        }\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        FbxExporter* pExporter = FbxExporter::Create( m_pManager, \"FBX Exporter\" );\r\n        if ( !pExporter->Initialize( outputFilepath.c_str(), fileFormatIDToUse, m_pManager->GetIOSettings() ) )\r\n        {\r\n            printf( \"Error! Failed to initialize exporter: %s\\n\\n\", pExporter->GetStatus().GetErrorString() );\r\n            return 1;\r\n        }\r\n\r\n        if ( pExporter->Export( pScene ) )\r\n        {\r\n            printf( \"Success!\\nIn: %s \\nOut (%s): %s\\n\\n\", inputFilepath.c_str(), outputFormat == FileFormat::Binary ? \"binary\" : \"ascii\", outputFilepath.c_str() );\r\n        }\r\n        else\r\n        {\r\n            printf( \"Error! File export failed: - %s\\n\\n\", pExporter->GetStatus().GetErrorString() );\r\n        }\r\n\r\n        pExporter->Destroy();\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        return 0;\r\n    }\r\n\r\n    bool IsFbxFile( std::string const& inputFilepath )\r\n    {\r\n        assert( !inputFilepath.empty() );\r\n        int readerID = -1;\r\n        auto pIOPluginRegistry = m_pManager->GetIOPluginRegistry();\r\n        pIOPluginRegistry->DetectReaderFileFormat( inputFilepath.c_str(), readerID );\r\n        return pIOPluginRegistry->ReaderIsFBX( readerID );\r\n    }\r\n\r\nprivate:\r\n\r\n    FbxConverter( FbxConverter const& ) = delete;\r\n    FbxConverter& operator=( FbxConverter const& ) = delete;\r\n\r\nprivate:\r\n\r\n    FbxManager*             m_pManager = nullptr;\r\n    int const               m_binaryWriteID = -1;\r\n    int const               m_asciiWriterID = -1;\r\n};\r\n\r\n//-------------------------------------------------------------------------\r\n\r\nstatic void PrintErrorAndHelp( char const* pErrorMessage = nullptr )\r\n{\r\n    printf( \"================================================\\n\" );\r\n    printf( \"FBX File Format Converter\\n\" );\r\n    printf( \"================================================\\n\" );\r\n    printf( \"2020 - Bobby Anguelov - MIT License\\n\\n\" );\r\n\r\n    if ( pErrorMessage != nullptr )\r\n    {\r\n        printf( \"Error! %s\\n\\n\", pErrorMessage );\r\n    }\r\n\r\n    printf( \"Convert: -c <path> [-o <output path>] {-binary|-ascii}\\n\" );\r\n    printf( \"Query: -q <path>\\n\" );\r\n}\r\n\r\nstatic void PrintFileFormat( std::string const& filePath )\r\n{\r\n    FileFormat const fileFormat = FileSystemHelpers::GetFileFormat( filePath.c_str() );\r\n\r\n    if ( fileFormat == FileFormat::Binary )\r\n    {\r\n        printf( \"%s - binary\\n\", filePath.c_str() );\r\n    }\r\n    else if ( fileFormat == FileFormat::Ascii )\r\n    {\r\n        printf( \"%s - ascii\\n\", filePath.c_str() );\r\n    }\r\n    else\r\n    {\r\n        printf( \"%s doesnt exist or is not an FBX file!\\n\", filePath.c_str() );\r\n    }\r\n}\r\n\r\n//-------------------------------------------------------------------------\r\n\r\nint main( int argc, char* argv[] )\r\n{\r\n    cli::Parser cmdParser( argc, argv );\r\n    cmdParser.disable_help();\r\n    cmdParser.set_optional<std::string>( \"c\", \"convert\", \"\" );\r\n    cmdParser.set_optional<std::string>( \"o\", \"output\", \"\" );\r\n    cmdParser.set_optional<std::string>( \"q\", \"query\", \"\" );\r\n    cmdParser.set_optional<bool>( \"binary\", \"\", false, \"\"  );\r\n    cmdParser.set_optional<bool>( \"ascii\", \"\", false, \"\" );\r\n\r\n    if ( cmdParser.run() )\r\n    {\r\n        FbxConverter fbxConverter;\r\n\r\n        //-------------------------------------------------------------------------\r\n\r\n        auto inputConvertPath = cmdParser.get<std::string>( \"c\" );\r\n        if ( !inputConvertPath.empty() )\r\n        {\r\n            bool const outputAsBinary = cmdParser.get<bool>( \"binary\" );\r\n            bool const outputAsAscii = cmdParser.get<bool>( \"ascii\" );\r\n\r\n            if ( outputAsAscii && outputAsBinary )\r\n            {\r\n                PrintErrorAndHelp( \"Having both -ascii and -binary arguments is not allowed.\" );\r\n            }\r\n            else if ( !outputAsAscii && !outputAsBinary )\r\n            {\r\n                PrintErrorAndHelp( \"Either -ascii or -binary required!\" );\r\n            }\r\n            else\r\n            {\r\n                FileFormat const outputFormat = outputAsBinary ? FileFormat::Binary : FileFormat::Ascii;\r\n\r\n                inputConvertPath = FileSystemHelpers::GetFullPathString( inputConvertPath );\r\n                if ( FileSystemHelpers::IsValidDirectoryPath( inputConvertPath ) )\r\n                {\r\n                    std::vector<std::string> directoryContents;\r\n                    FileSystemHelpers::GetDirectoryContents( inputConvertPath, directoryContents );\r\n\r\n                    auto outputPath = cmdParser.get<std::string>( \"o\" );\r\n                    if ( outputPath.empty() )\r\n                    {\r\n                        for ( auto& filePath : directoryContents )\r\n                        {\r\n                            if ( !fbxConverter.IsFbxFile( filePath.c_str() ) )\r\n                            {\r\n                                continue;\r\n                            }\r\n\r\n                            fbxConverter.ConvertFbxFile( filePath.c_str(), filePath.c_str(), outputFormat );\r\n                        }\r\n\r\n                        return 0;\r\n                    }\r\n                    else // Convert and copy\r\n                    {\r\n                        outputPath = FileSystemHelpers::GetFullPathString( outputPath );\r\n\r\n                        for ( auto& filePath : directoryContents )\r\n                        {\r\n                            if ( !fbxConverter.IsFbxFile( filePath ) )\r\n                            {\r\n                                continue;\r\n                            }\r\n\r\n                            std::string newOutputPath = filePath;\r\n                            newOutputPath.replace( 0, inputConvertPath.length() - 1, outputPath.c_str() );\r\n                            fbxConverter.ConvertFbxFile( filePath, newOutputPath, outputFormat );\r\n                        }\r\n\r\n                        return 0;\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    auto outputPath = cmdParser.get<std::string>( \"o\" );\r\n                    if ( outputPath.empty() )\r\n                    {\r\n                        return fbxConverter.ConvertFbxFile( inputConvertPath, inputConvertPath, outputFormat );\r\n                    }\r\n                    else\r\n                    {\r\n                        outputPath = FileSystemHelpers::GetFullPathString( outputPath );\r\n                        return fbxConverter.ConvertFbxFile( inputConvertPath, outputPath, outputFormat );\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        else // check for query cmd line arg\r\n        {\r\n            auto inputQueryPath = cmdParser.get<std::string>( \"q\" );\r\n            if ( !inputQueryPath.empty() )\r\n            {\r\n                inputQueryPath = FileSystemHelpers::GetFullPathString( inputQueryPath );\r\n                if ( FileSystemHelpers::IsValidDirectoryPath( inputQueryPath ) )\r\n                {\r\n                    std::vector<std::string> directoryContents;\r\n                    FileSystemHelpers::GetDirectoryContents( inputQueryPath, directoryContents );\r\n\r\n                    for ( auto& filePath : directoryContents )\r\n                    {\r\n                        if ( !fbxConverter.IsFbxFile( filePath ) )\r\n                        {\r\n                            continue;\r\n                        }\r\n\r\n                        PrintFileFormat( filePath );\r\n                    }\r\n                }\r\n                else \r\n                {\r\n                    PrintFileFormat( inputQueryPath );\r\n                }\r\n            }\r\n            else\r\n            {\r\n                PrintErrorAndHelp( \"Invalid Arguments!\" );\r\n            }\r\n        }\r\n\r\n        return 0;\r\n    }\r\n    else\r\n    {\r\n        PrintErrorAndHelp();\r\n    }\r\n\r\n    return 1;\r\n}"
  },
  {
    "path": "readme.md",
    "content": "# Fbx Format Converter\r\n\r\nThis project allows you to convert binary fbx files to asciis and vice versa. This is especially useful when trying to import fbx files into blender since blender cannot read ascii FBX files.\r\n\r\n## Features\r\n\r\n* Single file conversion between binary and ascii\r\n* Batch folder conversion\r\n* Single file/folder query\r\n\r\n## To build:\r\n\r\n* You need to have the FBX SDK installed (https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2020-0)\r\n\r\n* Open the FbxFormatConverter.props file and change the FBX_SDK_DIR macro to point to the FBXSDK install directory.\r\n\r\n* Open the sln file using visual studio and hit build.\r\n\r\n## Conversion:\r\n\r\nIf you want to convert an ascii file into a binary one or vice versa.\r\n\r\n`FbxFormatConverter.exe -c <filepath|folderpath> [-o <filepath|folderpath>] {-ascii|-binary}`\r\n\r\n* -c : convert the file/folder specified\r\n* -o : (optional) the outputpath for the converted files, if not supplied then the source file will be overwritten\r\n* -binary/-ascii : the required output file format. Only one is allowed.\r\n\r\n## Query:\r\n\r\nIf you want to find out if an FBX file is an ascii or a binary file.\r\n\r\n`FbxFormatConverter.exe -q <filepath|folderpath>`\r\n\r\n* -q : query the file/folder specified\r\n\r\n## Examples\r\n\r\nIf you want to covert file \"anim_temp_final_0_v2.fbx\" to binary.\r\n\r\n`FbxFormatConverter.exe -c \"c:\\anim_temp_final_0_v2.fbx\" -binary`\r\n\r\nIf you want to convert all the files in folder a to ascii and store the converted files in folder b:\r\n\r\n`FbxFormatConverter.exe -c \"c:\\a\" -o \"c:\\b\" -ascii`\r\n\r\nIf you want to know if file \"dancingbaby.fbx\" is a binary file.\r\n\r\n`FbxFormatConverter.exe -q \"c:\\dancingbaby.fbx\"`\r\n\r\n## Notes:\r\n\r\nThis project uses CmdParser ( https://github.com/FlorianRappl/CmdParser )"
  }
]