├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── FAT_definitions.cpp ├── FAT_definitions.h ├── IMGwcx.dsp ├── IMGwcx.dsw ├── IMGwcx.vcxproj ├── IMGwcx.vcxproj.filters ├── LICENSE.txt ├── ReadMe.md ├── fatimg_32.def ├── fatimg_64.def ├── fatimg_wcx.cpp ├── fatimg_wcx.sln ├── main_resources.rc ├── minimal_fixed_string.h ├── plugin_config.cpp ├── plugin_config.h ├── pluginst.inf ├── resource.h ├── string_tools.cpp ├── string_tools.h ├── sysio_winapi.cpp ├── sysio_winapi.h └── wcxhead.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # PVS-Studio 14 | # build* 15 | *.PVS-Studio.* 16 | *.i 17 | *.CLMonitoring.* 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Mono auto generated files 23 | mono_crash.* 24 | 25 | # Build results 26 | [Dd]ebug/ 27 | [Dd]ebugPublic/ 28 | [Rr]elease/ 29 | [Rr]eleases/ 30 | x64/ 31 | x86/ 32 | [Ww][Ii][Nn]32/ 33 | [Aa][Rr][Mm]/ 34 | [Aa][Rr][Mm]64/ 35 | bld/ 36 | [Bb]in/ 37 | [Oo]bj/ 38 | [Oo]ut/ 39 | [Ll]og/ 40 | [Ll]ogs/ 41 | 42 | # Visual Studio 2015/2017 cache/options directory 43 | .vs/ 44 | # Uncomment if you have tasks that create the project's static files in wwwroot 45 | #wwwroot/ 46 | 47 | # Visual Studio 2017 auto generated files 48 | Generated\ Files/ 49 | 50 | # MSTest test Results 51 | [Tt]est[Rr]esult*/ 52 | [Bb]uild[Ll]og.* 53 | 54 | # NUnit 55 | *.VisualState.xml 56 | TestResult.xml 57 | nunit-*.xml 58 | 59 | # Build Results of an ATL Project 60 | [Dd]ebugPS/ 61 | [Rr]eleasePS/ 62 | dlldata.c 63 | 64 | # Benchmark Results 65 | BenchmarkDotNet.Artifacts/ 66 | 67 | # .NET Core 68 | project.lock.json 69 | project.fragment.lock.json 70 | artifacts/ 71 | 72 | # ASP.NET Scaffolding 73 | ScaffoldingReadMe.txt 74 | 75 | # StyleCop 76 | StyleCopReport.xml 77 | 78 | # Files built by Visual Studio 79 | *_i.c 80 | *_p.c 81 | *_h.h 82 | *.ilk 83 | *.meta 84 | *.obj 85 | *.iobj 86 | *.pch 87 | *.pdb 88 | *.ipdb 89 | *.pgc 90 | *.pgd 91 | *.rsp 92 | *.sbr 93 | *.tlb 94 | *.tli 95 | *.tlh 96 | *.tmp 97 | *.tmp_proj 98 | *_wpftmp.csproj 99 | *.log 100 | *.vspscc 101 | *.vssscc 102 | .builds 103 | *.pidb 104 | *.svclog 105 | *.scc 106 | 107 | # Chutzpah Test files 108 | _Chutzpah* 109 | 110 | # Visual C++ cache files 111 | ipch/ 112 | *.aps 113 | *.ncb 114 | *.opendb 115 | *.opensdf 116 | *.sdf 117 | *.cachefile 118 | *.VC.db 119 | *.VC.VC.opendb 120 | 121 | # Visual Studio profiler 122 | *.psess 123 | *.vsp 124 | *.vspx 125 | *.sap 126 | 127 | # Visual Studio Trace Files 128 | *.e2e 129 | 130 | # TFS 2012 Local Workspace 131 | $tf/ 132 | 133 | # Guidance Automation Toolkit 134 | *.gpState 135 | 136 | # ReSharper is a .NET coding add-in 137 | _ReSharper*/ 138 | *.[Rr]e[Ss]harper 139 | *.DotSettings.user 140 | 141 | # TeamCity is a build add-in 142 | _TeamCity* 143 | 144 | # DotCover is a Code Coverage Tool 145 | *.dotCover 146 | 147 | # AxoCover is a Code Coverage Tool 148 | .axoCover/* 149 | !.axoCover/settings.json 150 | 151 | # Coverlet is a free, cross platform Code Coverage Tool 152 | coverage*.json 153 | coverage*.xml 154 | coverage*.info 155 | 156 | # Visual Studio code coverage results 157 | *.coverage 158 | *.coveragexml 159 | 160 | # NCrunch 161 | _NCrunch_* 162 | .*crunch*.local.xml 163 | nCrunchTemp_* 164 | 165 | # MightyMoose 166 | *.mm.* 167 | AutoTest.Net/ 168 | 169 | # Web workbench (sass) 170 | .sass-cache/ 171 | 172 | # Installshield output folder 173 | [Ee]xpress/ 174 | 175 | # DocProject is a documentation generator add-in 176 | DocProject/buildhelp/ 177 | DocProject/Help/*.HxT 178 | DocProject/Help/*.HxC 179 | DocProject/Help/*.hhc 180 | DocProject/Help/*.hhk 181 | DocProject/Help/*.hhp 182 | DocProject/Help/Html2 183 | DocProject/Help/html 184 | 185 | # Click-Once directory 186 | publish/ 187 | 188 | # Publish Web Output 189 | *.[Pp]ublish.xml 190 | *.azurePubxml 191 | # Note: Comment the next line if you want to checkin your web deploy settings, 192 | # but database connection strings (with potential passwords) will be unencrypted 193 | *.pubxml 194 | *.publishproj 195 | 196 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 197 | # checkin your Azure Web App publish settings, but sensitive information contained 198 | # in these scripts will be unencrypted 199 | PublishScripts/ 200 | 201 | # NuGet Packages 202 | *.nupkg 203 | # NuGet Symbol Packages 204 | *.snupkg 205 | # The packages folder can be ignored because of Package Restore 206 | **/[Pp]ackages/* 207 | # except build/, which is used as an MSBuild target. 208 | !**/[Pp]ackages/build/ 209 | # Uncomment if necessary however generally it will be regenerated when needed 210 | #!**/[Pp]ackages/repositories.config 211 | # NuGet v3's project.json files produces more ignorable files 212 | *.nuget.props 213 | *.nuget.targets 214 | 215 | # Microsoft Azure Build Output 216 | csx/ 217 | *.build.csdef 218 | 219 | # Microsoft Azure Emulator 220 | ecf/ 221 | rcf/ 222 | 223 | # Windows Store app package directories and files 224 | AppPackages/ 225 | BundleArtifacts/ 226 | Package.StoreAssociation.xml 227 | _pkginfo.txt 228 | *.appx 229 | *.appxbundle 230 | *.appxupload 231 | 232 | # Visual Studio cache files 233 | # files ending in .cache can be ignored 234 | *.[Cc]ache 235 | # but keep track of directories ending in .cache 236 | !?*.[Cc]ache/ 237 | 238 | # Others 239 | ClientBin/ 240 | ~$* 241 | *~ 242 | *.dbmdl 243 | *.dbproj.schemaview 244 | *.jfm 245 | *.pfx 246 | *.publishsettings 247 | orleans.codegen.cs 248 | 249 | # Including strong name files can present a security risk 250 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 251 | #*.snk 252 | 253 | # Since there are multiple workflows, uncomment next line to ignore bower_components 254 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 255 | #bower_components/ 256 | 257 | # RIA/Silverlight projects 258 | Generated_Code/ 259 | 260 | # Backup & report files from converting an old project file 261 | # to a newer Visual Studio version. Backup files are not needed, 262 | # because we have git ;-) 263 | _UpgradeReport_Files/ 264 | Backup*/ 265 | UpgradeLog*.XML 266 | UpgradeLog*.htm 267 | ServiceFabricBackup/ 268 | *.rptproj.bak 269 | 270 | # SQL Server files 271 | *.mdf 272 | *.ldf 273 | *.ndf 274 | 275 | # Business Intelligence projects 276 | *.rdl.data 277 | *.bim.layout 278 | *.bim_*.settings 279 | *.rptproj.rsuser 280 | *- [Bb]ackup.rdl 281 | *- [Bb]ackup ([0-9]).rdl 282 | *- [Bb]ackup ([0-9][0-9]).rdl 283 | 284 | # Microsoft Fakes 285 | FakesAssemblies/ 286 | 287 | # GhostDoc plugin setting file 288 | *.GhostDoc.xml 289 | 290 | # Node.js Tools for Visual Studio 291 | .ntvs_analysis.dat 292 | node_modules/ 293 | 294 | # Visual Studio 6 build log 295 | *.plg 296 | 297 | # Visual Studio 6 workspace options file 298 | *.opt 299 | 300 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 301 | *.vbw 302 | 303 | # Visual Studio LightSwitch build output 304 | **/*.HTMLClient/GeneratedArtifacts 305 | **/*.DesktopClient/GeneratedArtifacts 306 | **/*.DesktopClient/ModelManifest.xml 307 | **/*.Server/GeneratedArtifacts 308 | **/*.Server/ModelManifest.xml 309 | _Pvt_Extensions 310 | 311 | # Paket dependency manager 312 | .paket/paket.exe 313 | paket-files/ 314 | 315 | # FAKE - F# Make 316 | .fake/ 317 | 318 | # CodeRush personal settings 319 | .cr/personal 320 | 321 | # Python Tools for Visual Studio (PTVS) 322 | __pycache__/ 323 | *.pyc 324 | 325 | # Cake - Uncomment if you are using it 326 | # tools/** 327 | # !tools/packages.config 328 | 329 | # Tabs Studio 330 | *.tss 331 | 332 | # Telerik's JustMock configuration file 333 | *.jmconfig 334 | 335 | # BizTalk build output 336 | *.btp.cs 337 | *.btm.cs 338 | *.odx.cs 339 | *.xsd.cs 340 | 341 | # OpenCover UI analysis results 342 | OpenCover/ 343 | 344 | # Azure Stream Analytics local run output 345 | ASALocalRun/ 346 | 347 | # MSBuild Binary and Structured Log 348 | *.binlog 349 | 350 | # NVidia Nsight GPU debugger configuration file 351 | *.nvuser 352 | 353 | # MFractors (Xamarin productivity tool) working folder 354 | .mfractor/ 355 | 356 | # Local History for Visual Studio 357 | .localhistory/ 358 | 359 | # BeatPulse healthcheck temp database 360 | healthchecksdb 361 | 362 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 363 | MigrationBackup/ 364 | 365 | # Ionide (cross platform F# VS Code tools) working folder 366 | .ionide/ 367 | 368 | # Fody - auto-generated XML schema 369 | FodyWeavers.xsd 370 | 371 | # Local tests folder 372 | /b 373 | /b32gcc 374 | /b64gcc 375 | /b32msvc 376 | /b64msvc 377 | /distr 378 | /b32 379 | /b64 380 | /img.wcx64 381 | /img.wcx 382 | *.map 383 | /tbuild 384 | /make_distr.sh 385 | /fatimg.wcx 386 | /fatimg.wcx64 387 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Configure by: 2 | # Using MSVC 2019 and create 64-bit plugin: 3 | # cmake -A x64 .. -G"Visual Studio 16" 4 | # Using MSVC 2019 and create 32-bit plugin: 5 | # cmake -A Win32 .. -G"Visual Studio 16" 6 | # 7 | # To enable FLTK usage: 8 | # cmake -A x64 .. -G"Visual Studio 16" -DFLTK_ENABLED_EXPERIMENTAL=1 9 | # cmake -A Win32 .. -G"Visual Studio 16" -DFLTK_ENABLED_EXPERIMENTAL=1 10 | # 11 | # Build by: 12 | # cmake --build . --config Release 13 | # or any of: 14 | # cmake --build . --config [Debug|RelWithDebInfo|MinSizeRel] 15 | # otherwise ('cmake --build .') could lead to /MD vs /MDd vs others mismatch: 16 | # `warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs fltk` 17 | 18 | cmake_minimum_required(VERSION 3.15) 19 | project(FATimage) 20 | 21 | set(CMAKE_CXX_STANDARD 20) 22 | 23 | set(SOURCE_FILES FAT_definitions.cpp FAT_definitions.h fatimg_wcx.cpp minimal_fixed_string.h resource.h sysio_winapi.cpp sysio_winapi.h wcxhead.h main_resources.rc 24 | string_tools.cpp string_tools.h plugin_config.cpp plugin_config.h ) 25 | 26 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 27 | set(SOURCE_FILES ${SOURCE_FILES} fatimg_64.def) 28 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 29 | set(SOURCE_FILES ${SOURCE_FILES} fatimg_32.def) 30 | endif() 31 | 32 | add_library(fatimg_wcx SHARED ${SOURCE_FILES} ) 33 | set_target_properties(fatimg_wcx PROPERTIES OUTPUT_NAME fatimg) 34 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 35 | set_target_properties(fatimg_wcx PROPERTIES SUFFIX .wcx64 PREFIX "") 36 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) 37 | set_target_properties(fatimg_wcx PROPERTIES SUFFIX .wcx PREFIX "") 38 | endif() 39 | 40 | if( DEFINED FLTK_ENABLED_EXPERIMENTAL) 41 | find_package(FLTK CONFIG) 42 | 43 | if( FLTK_FOUND ) 44 | target_compile_definitions(fatimg_wcx PRIVATE -DFLTK_ENABLED_EXPERIMENTAL=1) 45 | target_include_directories(fatimg_wcx PRIVATE ${FLTK_INCLUDE_DIR}) 46 | target_link_libraries(fatimg_wcx PRIVATE fltk fltk_gl fltk_forms fltk_images) 47 | endif() 48 | 49 | endif() 50 | 51 | # https://www.ghisler.ch/wiki/index.php?title=Plugins_Automated_Installation -------------------------------------------------------------------------------- /FAT_definitions.cpp: -------------------------------------------------------------------------------- 1 | // This is a personal academic project. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 3 | /* 4 | * Floppy disk images unpack plugin for the Total Commander. 5 | * Copyright (c) 2002, IvGzury ( ivgzury@hotmail.com ) 6 | * Copyright (c) 2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 7 | * 8 | * Oleg Farenyuk's code is released under the MIT License. 9 | * 10 | * Original IvGzury copyright message: 11 | * This program is absolutely free software. 12 | * If you have any remarks or problems, please don't 13 | * hesitate to send me an email. 14 | */ 15 | 16 | #include "FAT_definitions.h" 17 | -------------------------------------------------------------------------------- /FAT_definitions.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indrekis/FATImage_TCMD_plugin/622eaea19b42b4b09a1b5d5c1f3ab0bcad211e77/FAT_definitions.h -------------------------------------------------------------------------------- /IMGwcx.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="IMGwcx" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 6 | 7 | CFG=IMGwcx - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "IMGwcx.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "IMGwcx.mak" CFG="IMGwcx - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "IMGwcx - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") 21 | !MESSAGE "IMGwcx - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | MTL=midl.exe 30 | RSC=rc.exe 31 | 32 | !IF "$(CFG)" == "IMGwcx - Win32 Release" 33 | 34 | # PROP BASE Use_MFC 0 35 | # PROP BASE Use_Debug_Libraries 0 36 | # PROP BASE Output_Dir "Release" 37 | # PROP BASE Intermediate_Dir "Release" 38 | # PROP BASE Target_Dir "" 39 | # PROP Use_MFC 0 40 | # PROP Use_Debug_Libraries 0 41 | # PROP Output_Dir "Release" 42 | # PROP Intermediate_Dir "Release" 43 | # PROP Ignore_Export_Lib 0 44 | # PROP Target_Dir "" 45 | # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMGWCX_EXPORTS" /Yu"stdafx.h" /FD /c 46 | # ADD CPP /nologo /MT /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMGWCX_EXPORTS" /FR /Yu"stdafx.h" /FD /c 47 | # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 48 | # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 49 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 50 | # ADD RSC /l 0x409 /d "NDEBUG" 51 | BSC32=bscmake.exe 52 | # ADD BASE BSC32 /nologo 53 | # ADD BSC32 /nologo 54 | LINK32=link.exe 55 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 56 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"img.wcx" 57 | 58 | !ELSEIF "$(CFG)" == "IMGwcx - Win32 Debug" 59 | 60 | # PROP BASE Use_MFC 0 61 | # PROP BASE Use_Debug_Libraries 1 62 | # PROP BASE Output_Dir "Debug" 63 | # PROP BASE Intermediate_Dir "Debug" 64 | # PROP BASE Target_Dir "" 65 | # PROP Use_MFC 0 66 | # PROP Use_Debug_Libraries 1 67 | # PROP Output_Dir "Debug" 68 | # PROP Intermediate_Dir "Debug" 69 | # PROP Ignore_Export_Lib 0 70 | # PROP Target_Dir "" 71 | # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMGWCX_EXPORTS" /Yu"stdafx.h" /FD /GZ /c 72 | # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "IMGWCX_EXPORTS" /Yu"stdafx.h" /FD /GZ /c 73 | # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 74 | # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 75 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 76 | # ADD RSC /l 0x409 /d "_DEBUG" 77 | BSC32=bscmake.exe 78 | # ADD BASE BSC32 /nologo 79 | # ADD BSC32 /nologo 80 | LINK32=link.exe 81 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept 82 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"img.wcx" /pdbtype:sept 83 | 84 | !ENDIF 85 | 86 | # Begin Target 87 | 88 | # Name "IMGwcx - Win32 Release" 89 | # Name "IMGwcx - Win32 Debug" 90 | # Begin Group "Source Files" 91 | 92 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 93 | # Begin Source File 94 | 95 | SOURCE=.\IMGwcx.cpp 96 | # End Source File 97 | # Begin Source File 98 | 99 | SOURCE=.\imgwcx.def 100 | # End Source File 101 | # Begin Source File 102 | 103 | SOURCE=.\StdAfx.cpp 104 | # ADD CPP /Yc"stdafx.h" 105 | # End Source File 106 | # End Group 107 | # Begin Group "Header Files" 108 | 109 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 110 | # Begin Source File 111 | 112 | SOURCE=.\StdAfx.h 113 | # End Source File 114 | # Begin Source File 115 | 116 | SOURCE=.\wcxhead.h 117 | # End Source File 118 | # End Group 119 | # Begin Group "Resource Files" 120 | 121 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 122 | # Begin Source File 123 | 124 | SOURCE=.\Script1.rc 125 | # End Source File 126 | # End Group 127 | # Begin Source File 128 | 129 | SOURCE=.\ReadMe.txt 130 | # End Source File 131 | # End Target 132 | # End Project 133 | -------------------------------------------------------------------------------- /IMGwcx.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "IMGwcx"=".\IMGwcx.dsp" - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /IMGwcx.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | {1EDF664D-9C37-4752-A938-DE7CA10C9895} 25 | 10.0 26 | fatimg_wcx 27 | 28 | 29 | 30 | DynamicLibrary 31 | v143 32 | false 33 | MultiByte 34 | 35 | 36 | DynamicLibrary 37 | v143 38 | false 39 | MultiByte 40 | 41 | 42 | DynamicLibrary 43 | v143 44 | false 45 | MultiByte 46 | 47 | 48 | DynamicLibrary 49 | v143 50 | false 51 | MultiByte 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | .\Debug\ 75 | .\Debug\ 76 | true 77 | .wcx 78 | 79 | 80 | true 81 | .wcx64 82 | img 83 | 84 | 85 | .\Release\ 86 | .\Release\ 87 | false 88 | .wcx 89 | 90 | 91 | false 92 | img 93 | .wcx64 94 | 95 | 96 | true 97 | false 98 | 99 | 100 | 101 | MultiThreadedDebugDLL 102 | Default 103 | false 104 | Disabled 105 | true 106 | Level3 107 | false 108 | ProgramDatabase 109 | WIN32;_DEBUG;_WINDOWS;_USRDLL;IMGWCX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 110 | .\Debug\ 111 | .\Debug\IMGwcx.pch 112 | NotUsing 113 | stdafx.h 114 | .\Debug\ 115 | .\Debug\ 116 | EnableFastChecks 117 | stdcpp20 118 | 119 | 120 | true 121 | _DEBUG;%(PreprocessorDefinitions) 122 | .\Debug\IMGwcx.tlb 123 | true 124 | Win32 125 | 126 | 127 | 0x0409 128 | _DEBUG;%(PreprocessorDefinitions) 129 | 130 | 131 | true 132 | .\Debug\IMGwcx.bsc 133 | 134 | 135 | true 136 | true 137 | true 138 | Console 139 | fatimg.wcx 140 | .\Debug\img.lib 141 | odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 142 | fatimg_32.def 143 | true 144 | 145 | 146 | 147 | 148 | MultiThreadedDebugDLL 149 | Default 150 | false 151 | Disabled 152 | true 153 | Level3 154 | ProgramDatabase 155 | WIN32;_DEBUG;_WINDOWS;_USRDLL;IMGWCX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 156 | .\Debug\ 157 | .\Debug\IMGwcx.pch 158 | NotUsing 159 | stdafx.h 160 | .\Debug\ 161 | .\Debug\ 162 | EnableFastChecks 163 | stdcpp20 164 | 165 | 166 | true 167 | _DEBUG;%(PreprocessorDefinitions) 168 | .\Debug\IMGwcx.tlb 169 | true 170 | 171 | 172 | 0x0409 173 | _DEBUG;%(PreprocessorDefinitions) 174 | 175 | 176 | true 177 | .\Debug\IMGwcx.bsc 178 | 179 | 180 | true 181 | true 182 | true 183 | Console 184 | fatimg.wcx64 185 | .\Debug\img.lib 186 | odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 187 | fatimg_64.def 188 | true 189 | 190 | 191 | 192 | 193 | MultiThreadedDLL 194 | Default 195 | true 196 | true 197 | MinSpace 198 | true 199 | Level3 200 | WIN32;NDEBUG;_WINDOWS;_USRDLL;IMGWCX_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 201 | .\Release\ 202 | true 203 | .\Release\IMGwcx.pch 204 | NotUsing 205 | stdafx.h 206 | .\Release\ 207 | .\Release\ 208 | stdcpp20 209 | 210 | 211 | true 212 | NDEBUG;%(PreprocessorDefinitions) 213 | .\Release\IMGwcx.tlb 214 | true 215 | Win32 216 | 217 | 218 | 0x0409 219 | NDEBUG;%(PreprocessorDefinitions) 220 | 221 | 222 | true 223 | .\Release\IMGwcx.bsc 224 | 225 | 226 | true 227 | true 228 | Console 229 | fatimg.wcx 230 | .\Release\img.lib 231 | odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 232 | fatimg_32.def 233 | true 234 | 235 | 236 | 237 | 238 | MultiThreadedDLL 239 | Default 240 | true 241 | true 242 | MinSpace 243 | true 244 | Level3 245 | WIN32;NDEBUG;_WINDOWS;_USRDLL;IMGWCX_EXPORTS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 246 | .\Release\ 247 | true 248 | .\Release\IMGwcx.pch 249 | NotUsing 250 | stdafx.h 251 | .\Release\ 252 | .\Release\ 253 | stdcpp20 254 | 255 | 256 | true 257 | NDEBUG;%(PreprocessorDefinitions) 258 | .\Release\IMGwcx.tlb 259 | true 260 | 261 | 262 | 0x0409 263 | NDEBUG;%(PreprocessorDefinitions) 264 | 265 | 266 | true 267 | .\Release\IMGwcx.bsc 268 | 269 | 270 | true 271 | true 272 | Console 273 | fatimg.wcx64 274 | .\Release\img.lib 275 | %(AdditionalDependencies) 276 | fatimg_64.def 277 | true 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /IMGwcx.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {49953601-f5a2-4c01-b555-f50362f56a7d} 6 | cpp;c;cxx;rc;def;r;odl;idl;hpj;bat 7 | 8 | 9 | {623f4363-2b91-4041-8da5-930b51a0ae3e} 10 | h;hpp;hxx;hm;inl 11 | 12 | 13 | {bbd63ed4-96f8-4ec6-a16f-2f095660d863} 14 | ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Resource Files 60 | 61 | 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * Floppy disk images unpack plugin for the Total Commander. 3 | * Copyright (c) 2002, IvGzury ( ivgzury@hotmail.com ) 4 | * Copyright (c) 2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 5 | * 6 | * Oleg Farenyuk's code is released under the MIT License: 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | * SOFTWARE. 24 | * 25 | * Original IvGzury copyright message: 26 | * This program is absolutely free software. 27 | * If you have any remarks or problems, please don't 28 | * hesitate to send me an email. 29 | */ 30 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | FATImage is a wcx (archive) plugin for 64-bit and 32-bit Total Commander (TCmd) 5 | supporting access to the floppy disk images and FAT images in general, including partitioned ones. 6 | > There are several such good plugins for the 32-bit TCmd, but none (to the best of my knowledge) for the 64-bit TCmd. 7 | > > IMG Plugin for Total Commander (TCmd) by IvGzury was used as a starting point because its sources were available. 8 | 9 | Supports: FAT12, FAT16, FAT32, VFAT. 10 | 11 | Partial Unicode support for the FAT32 -- UCS-16 symbols in LFNs are converted to the local codepage. 12 | 13 | Supports DOS 1.xx images without BPB. 14 | > Support is based on the media descriptor in the FAT table and image size. 15 | > 16 | >Supports several optional exceptions for the popular quirks of historical disk images from the retro sites. 17 | 18 | Supports MBR-based partitions. Volumes with unknown or unsupported filesystems are shown as such. 19 | 20 | The plugin supports searching for the boot sector in the image. This is intended to help open images containing some metadata at the beginning, added by imaging tools. 21 | > WinImage demonstrates the same behavior. The boot sector for this search is determined by the following pattern of size 512 bytes exactly: 22 | > 23 | > `0xB8, 0xx, 0x90, 0xx ... 0xx, 0x55, 0xAA` 24 | > 25 | > where 0xx means any byte. 26 | 27 | Additional information in the author's blog (in Ukrainian): "[Анонс -- 64-бітний плагін Total Commander для роботи із образами FAT](https://indrekis2.blogspot.com/2022/08/64-total-commander-fat.html)" 28 | 29 | Installation 30 | ============ 31 | 32 | As usual for the TCmd plugins: 33 | * Manually: 34 | 1. Unzip the WCX to the directory of your choice (for example, c:\wincmd\plugins\wcx) 35 | 2. In TCmd, choose Configuration - Options 36 | 3. Open the 'Packer' page 37 | 4. Click 'Configure packer extension WCXs' 38 | 5. Type 'img' as the extension 39 | 6. Click 'new type', and select the img.wcx64 (img.wcx for 32-bit TCmd) 40 | 7. Click OK 41 | * Using automated install: 42 | 1. Open the archive with the plugin in TCmd -- it will propose to install the plugin. 43 | 44 | Configuration is stored in the `fatdiskimg.ini` file in the configuration path provided by the TCmd (usually -- the same place where wincmd.ini is located). If the configuration file is damaged or absent, it is recreated with default values. 45 | 46 | Works in Double Commander for Windows. 47 | 48 | Binary releases available [here](https://github.com/indrekis/FDDImage_TCMD_plugin/releases). 49 | 50 | This program is distributed in the hope that it will be useful, 51 | but WITHOUT ANY WARRANTY; without even the implied warranty of 52 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 53 | 54 | Plugin configuration 55 | ==================== 56 | 57 | The configuration file, named fatdiskimg.ini, is searched at the path provided by the TCmd (most often -- the path where wincmd.ini is located). If the configuration file is absent or incorrect, it is created with the default configuration. 58 | 59 | Except for the logging options, currently, the plugin rereads the configuration before opening each image (archive). 60 | 61 | Example configuration file: 62 | ``` 63 | [FAT_disk_img_plugin] 64 | ignore_boot_signature=1 65 | use_VFAT=1 66 | process_DOS1xx_images=1 67 | process_DOS1xx_exceptions=1 68 | process_MBR=1 69 | search_for_boot_sector=1 70 | search_for_boot_sector_range=65536 71 | allow_dialogs=0 72 | allow_GUI_log=1 73 | log_file_path=D:\Temp\fatimg.txt 74 | debug_level=0 75 | ``` 76 | 77 | * `ignore_boot_signature`. If the first 512-byte sector of the image does not contain 0x55AA and ignore_boot_signature == 0, the image is treated as not a FAT volume, even if the BPB data looks consistent. 78 | * `use_VFAT` -- if 1, long file names are processed (regardless of the FAT type). 79 | * `process_DOS1xx_images == 1` allows to interpret image with exact size, equal to: 160Kb, 180Kb, 320Kb, or 360Kb as a pre-BPB FAT image. Such images mostly came from the DOS 1.xx epoch disks. Disk format is then detected based on the [Media descriptor byte](https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#FATID) -- the first byte of the FAT, which is considered situated in the first byte of the second image sector. 80 | * It is a much less reliable format detection criterion than the full BPB, so enabling this option can interfere with the normal image processing, though the author never met with such a situation. 81 | * MC/PC-DOS versions 2.00-3.20 [sometimes created bad BPBs](http://www.os2museum.com/wp/dos-boot-sector-bpb-and-the-media-descriptor-byte/), making the media descriptors the main source of disk format information. 82 | * process_DOS1xx_exceptions=1 -- enables DOS 1.xx non-BPB images processing exceptions targeted at supporting the popular quirks of historical disk images from the retro sites. Not recommended for typical users. 83 | * `process_MBR == 1` -- if the disk is not a correct non-partitioned disk image, try to interpret it as an MBR-based partitioned image. 84 | * `search_for_boot_sector==1` -- if the disk image does not contain the correct boot sector or the MBR at the beginning, attempt to find the boot sector in the image file by the pattern `0xB8, 0xx, 0x90, 0xx ... 0xx, 0x55, 0xAA`, where 0xx means any byte. This helps to open images that contain some meta information before the image, but the image itself is not altered. Search for the MBR is not supported, but if there is a partitioned image after the metainformation, it can find the first FAT partition of the image. Not recommended for typical users. 85 | * `search_for_boot_sector_range==65536` -- range of the bootsector search, in bytes. The default value is 64kb. It is not recommended to increase this value substantially beyond this value. 86 | * Not only does it slow down working with the images, but it can also lead to false detections. 87 | * For example, utilities like `fdisk`, `sys`, or `format` can contain bootsector copies required for them to perform their duties. 88 | * `allow_dialogs==1` -- if FLKT support is enabled while building, enable dialogs on some image peculiarities, like the absence of the 0x55AA signature. 89 | * `allow_txt_log==1` -- allows detailed log output, describing imager properties and anomalies. It can noticeably slow down the plugin. Not for general use, can lead to problems. It is useful for in-depth image analysis. 90 | * Additionally, for the debug builds (without NDEBUG defined), important image analysis events are logged to the debugger console. In addition to using a full-fledged debugger, debugging output can be seen using [SimpleProgramDebugger](http://www.nirsoft.net/utils/simple_program_debugger.html). 91 | * `log_file_path=` -- logging filename. If opening this file for writing fails, logging is disabled (allow_txt_log==0). The file is created from scratch at the first use of the plugin during the current TCmd session. 92 | * `debug_level` -- not used now. 93 | 94 | Compilation 95 | =========== 96 | 97 | Code can be compiled using the Visual Studio project or CMakeLists.txt (tested using MSVC and MinGW). 98 | 99 | Uses C++20, with no obligatory external dependencies. 100 | 101 | As an experimental and optional feature, [FLTK](https://www.fltk.org/) is used to create dialogs. Using it can lead to instabilities because of multi-threading issues, so this feature is not for the general public. 102 | 103 | Examples of the command lines to compile using CMake are in the CMakeLists.txt. 104 | 105 | Preparing images for tests 106 | ========================== 107 | 108 | The plugin was tested using two kinds of images: 109 | * Images of virtual machines and emulators used for different tasks. 110 | * Historical floppy images from the retro-computing sites: [WinWorld](https://winworldpc.com/home), [BetaArchive](https://www.betaarchive.com/database/browse.php), [Old-DOS](http://old-dos.ru/), [VETUSWARE](https://vetusware.com/), [Bitsavers](http://www.bitsavers.org/bits/) 111 | 112 | The plugin is tested on over a thousand floppy images and dozens of HDD images, including custom-made ones with up to eleven partitions. 113 | 114 | ## Linux 115 | Linux loopback devices are a convenient approach to making test images. 116 | 117 | ### Example 1 -- partitioned image 118 | 119 | Create an image 1 GB in size: 120 | 121 | `dd if=/dev/zero of=image_file.img bs=100M count=10` 122 | 123 | Create a loopback device, connected to this file: 124 | 125 | `sudo losetup -fP image_file.img` 126 | 127 | Partition disk (put your device name in place of loop0): 128 | 129 | `sudo fdisk /dev/loop0` 130 | 131 | To check existing loopback devices: 132 | 133 | `losetup -a` 134 | 135 | On using fdisk, see [Partitioning with fdisk HOWTO](https://tldp.org/HOWTO/Partition/fdisk_partitioning.html) and [fdisk(8) man](https://man7.org/linux/man-pages/man8/fdisk.8.html). 136 | 137 | After the partitioning, loopback devices for partitions would have names like: 138 | 139 | `/dev/loop0p1 /dev/loop0p2 /dev/loop0p3 /dev/loop0p4 /dev/loop0p5 /dev/loop0p6 /dev/loop0p7 /dev/loop0p8 /dev/loop0p9 /dev/loop0p10 /dev/loop0p11` 140 | 141 | Remember the special role of loop0p4 -- it is an extended partition, containing loop0p5 and so on. 142 | 143 | To create FAT12/FAT16/FAT32/, use the following commands, respectively: 144 | 145 | ``` 146 | sudo mkfs.fat -F 12 /dev/loop0p9 147 | sudo mkfs.fat -F 16 /dev/loop0p10 148 | sudo mkfs.fat -F 32 /dev/loop0p11 149 | ``` 150 | 151 | Remember to use the correct partition device. More details: [dosfstools](https://github.com/dosfstools/dosfstools) 152 | 153 | To populate image partitions with the files, one can mount it and use it as any other Linux volume: 154 | 155 | ``` 156 | mkdir ~/virtual_disk1 157 | sudo mount -o loop /dev/loop0p10 ~/virtual_disk1 158 | ``` 159 | 160 | Lately, unmount it by: 161 | 162 | `sudo umount ~/virtual_disk1` 163 | 164 | `sudo losetup -d /dev/loop0` 165 | 166 | The exact command lines could depend on your Linux distribution. 167 | 168 | ### Example 1 -- nonpartitioned floppy image 169 | 170 | ``` 171 | dd if=/dev/zero of=floppy_144.img bs=1K count=1440 172 | sudo losetup -fP floppy_144.img 173 | sudo mkfs.fat -F 12 /dev/loop0 174 | mkdir ./fdd 175 | sudo mount -o loop ./fdd /dev/loop0 176 | 177 | 178 | 179 | sudo umount ./fdd 180 | sudo losetup -d /dev/loop0 181 | ``` 182 | 183 | ### Other 184 | 185 | Remove loopback device (put your device name in place of loop0): 186 | `sudo losetup -d /dev/loop0` 187 | 188 | To create an ext4/3/2 filesystem, use: 189 | 190 | ``` 191 | sudo mkfs.ext4 /dev/loop0p2 192 | sudo mkfs.ext3 /dev/loop0p3 193 | sudo mkfs.ext2 /dev/loop0p5 194 | ``` 195 | 196 | To create NTFS or exFAT: 197 | 198 | ``` 199 | sudo mkfs.ntfs /dev/loop0p10 200 | sudo mkfs.exfat /dev/loop0p10 201 | ``` 202 | 203 | To check the properties of the mounted loopback partition: 204 | 205 | `df -hP ~/virtual_disk1` 206 | 207 | ## Windows 208 | 209 | Under MS Windows, free (as a beer) [OSFMount](https://www.osforensics.com/tools/mount-disk-images.html) can be used to mount single-partition and multi-partition images. Less capable but open-source similar tool -- [ImDisk](https://sourceforge.net/projects/imdisk-toolkit/). 210 | 211 | Other imaging tools used during the tests were famous [WinImage](https://www.winimage.com/) and less known, but free (as a beer), DiskExplorer by junnno (no known site, can be downloaded [here](https://vetusware.com/download/Disk%20Explorer%201.69E/?id=16440)). 212 | 213 | 214 | Problems and limitations 215 | ======================== 216 | * Read-only. 217 | * Does not support exFAT. 218 | * No GPT support. 219 | * Does not yet support CHS partitions -- only LBA. 220 | * The absolute majority of HDDs created in the 1990s and later are LBA. 221 | * Partial support of Unicode in filenames, the code implements only ANSI functions for now. 222 | * As a result, the path is limited to 260-1 symbols max. 223 | * No support for the 8" images, including 86-DOS and CP/M images. 224 | * Directories data, time, and some attributes are not set properly. 225 | * Not yet tested on large (close to 2 TB) images. 226 | * 32-bit plugin version does not support background operation -- TCmd crashes or hangs every time the plugin is used if they are allowed. 227 | 228 | 229 | -------------------------------------------------------------------------------- /fatimg_32.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | OpenArchive 3 | ReadHeader 4 | ProcessFile 5 | CloseArchive 6 | SetChangeVolProc 7 | SetProcessDataProc 8 | PackSetDefaultParams 9 | CanYouHandleThisFile 10 | GetPackerCaps -------------------------------------------------------------------------------- /fatimg_64.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | OpenArchive 3 | ReadHeader 4 | ProcessFile 5 | CloseArchive 6 | SetChangeVolProc 7 | SetProcessDataProc 8 | PackSetDefaultParams 9 | GetBackgroundFlags 10 | CanYouHandleThisFile 11 | GetPackerCaps -------------------------------------------------------------------------------- /fatimg_wcx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indrekis/FATImage_TCMD_plugin/622eaea19b42b4b09a1b5d5c1f3ab0bcad211e77/fatimg_wcx.cpp -------------------------------------------------------------------------------- /fatimg_wcx.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.32602.291 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IMGwcx", "IMGwcx.vcxproj", "{1EDF664D-9C37-4752-A938-DE7CA10C9895}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Debug|x64.ActiveCfg = Debug|x64 17 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Debug|x64.Build.0 = Debug|x64 18 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Debug|x86.ActiveCfg = Debug|Win32 19 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Debug|x86.Build.0 = Debug|Win32 20 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Release|x64.ActiveCfg = Release|x64 21 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Release|x64.Build.0 = Release|x64 22 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Release|x86.ActiveCfg = Release|Win32 23 | {1EDF664D-9C37-4752-A938-DE7CA10C9895}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {35A8D3E3-BEA9-4CD9-A22F-6C739E992084} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /main_resources.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indrekis/FATImage_TCMD_plugin/622eaea19b42b4b09a1b5d5c1f3ab0bcad211e77/main_resources.rc -------------------------------------------------------------------------------- /minimal_fixed_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef MINIMAL_FIXED_STRING_H_INCLUDED 4 | #define MINIMAL_FIXED_STRING_H_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | class minimal_fixed_string_t { 12 | std::array data_m = { '\0' }; // Should always be a C-string -- with '\0' 13 | size_t size_m = 0; 14 | public: 15 | static const size_t npos = -1; 16 | minimal_fixed_string_t() = default; 17 | minimal_fixed_string_t(const minimal_fixed_string_t&) = default; 18 | minimal_fixed_string_t(const char* str) { 19 | push_back(str); 20 | } 21 | constexpr size_t size() const { return size_m; } 22 | constexpr size_t capacity() const { return data_m.size() - 1; } 23 | constexpr bool is_empty() const { return size_m == 0; } 24 | constexpr char& operator[](size_t idx) { return data_m[idx]; } 25 | constexpr const char& operator[](size_t idx) const { return data_m[idx]; } 26 | constexpr const char* data() const { return data_m.data(); } 27 | constexpr char* data() { return data_m.data(); } 28 | bool push_back(char c) { 29 | if (size() == capacity()) return false; 30 | data_m[size_m++] = c; 31 | data_m[size_m] = '\0'; 32 | return true; 33 | } 34 | bool push_back(const char* str) { 35 | data_m[size_m] = '\0'; 36 | // +1 -- for strcpy_s, note it we have place for 0 anyway 37 | auto res = !strcpy_s(data() + size(), capacity() - size() + 1, str); 38 | size_m += strnlen_s(data() + size(), capacity() - size()); 39 | return res; 40 | } 41 | template 42 | bool push_back(const minimal_fixed_string_t& fixed_str) { 43 | data_m[size_m] = '\0'; 44 | auto res = !strcpy_s(data() + size(), capacity() - size() + 1, fixed_str.data()); 45 | size_m += strnlen_s(data() + size(), capacity() - size()); 46 | return res; 47 | } 48 | void clear() { 49 | size_m = 0; 50 | data_m[size_m] = '\0'; 51 | } 52 | void shrink_to(size_t new_size) { 53 | if (new_size > size_m) 54 | return; 55 | size_m = new_size; 56 | data_m[size_m] = '\0'; 57 | } 58 | void pop_back() { 59 | if (size_m == 0) 60 | return; 61 | --size_m; 62 | data_m[size_m] = '\0'; 63 | } 64 | size_t find_last(char c) const { 65 | const char* last = strrchr(data(), c); 66 | if (last == nullptr) 67 | return npos; 68 | else 69 | return last - data(); 70 | } 71 | }; 72 | 73 | #endif -------------------------------------------------------------------------------- /plugin_config.cpp: -------------------------------------------------------------------------------- 1 | // This is a personal academic project. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 3 | /* 4 | * Copyright (c) 2017-2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 5 | * 6 | * The code is released under the MIT License. 7 | */ 8 | 9 | #include "plugin_config.h" 10 | #include "string_tools.h" 11 | 12 | #ifdef _WIN32 13 | #include "sysio_winapi.h" 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace { 23 | using parse_string_ret_t = std::pair>; 24 | 25 | parse_string_ret_t parse_string(std::string arg) { // Note: we need copy here -- let compiler create it for us 26 | constexpr char separator = '='; // Just for the readability 27 | constexpr char commenter1 = '#'; 28 | constexpr char commenter2 = '['; // Skip sections for now 29 | 30 | auto comment_pos = arg.find(commenter1); 31 | if (comment_pos != std::string::npos) 32 | arg.erase(comment_pos); //! Remove comment 33 | comment_pos = arg.find(commenter2); 34 | if (comment_pos != std::string::npos) 35 | arg.erase(comment_pos); //! Remove sections 36 | 37 | auto sep_pos = arg.find(separator); 38 | if (sep_pos == std::string::npos) { 39 | return parse_string_ret_t{ trim(arg), std::nullopt }; 40 | } 41 | auto left_part = arg.substr(0, sep_pos); 42 | auto right_part = arg.substr(sep_pos + 1, std::string::npos); 43 | return parse_string_ret_t{ trim(left_part), trim(right_part) }; 44 | } 45 | 46 | } 47 | 48 | 49 | 50 | int plugin_config_t::file_to_options_map(std::FILE* cf) { 51 | using namespace std::string_literals; 52 | int line_size = 1024; // Limit for the string 53 | std::unique_ptr line_ptr = std::make_unique(line_size); 54 | while ( std::fgets(line_ptr.get(), line_size, cf) ) { 55 | auto pr = parse_string(line_ptr.get()); 56 | if (pr.first.empty()) { 57 | if (!pr.second) 58 | continue; 59 | else 60 | return 1; // throw std::runtime_error{ "Wrong config line -- no option name: "s + line_ptr.get() }; // "=..." 61 | } 62 | else if (!pr.second) { 63 | return 2; // throw std::runtime_error{ "Wrong config line -- no '=': "s + line_ptr.get() }; // "abc" -- no '=' 64 | } 65 | else if (pr.second->empty()) { 66 | return 3; // throw std::runtime_error{ "Wrong config option value: "s + line_ptr.get() }; // "key=" 67 | } 68 | if (options_map.count(pr.first)) { 69 | return 4; // throw std::runtime_error{ "Duplicated option name: "s + pr.first + " = " //-V112 70 | // + *pr.second + "; prev. val: " + options_map[pr.first] }; 71 | } 72 | options_map[pr.first] = *pr.second; 73 | } 74 | return 0; 75 | } 76 | 77 | template 78 | T plugin_config_t::get_option_from_map(const std::string& option_name) const { 79 | if (options_map.count(option_name) == 0) { 80 | throw std::runtime_error("Option not found: " + option_name); 81 | } 82 | auto elem_itr = options_map.find(option_name); 83 | if (elem_itr != options_map.end()) { 84 | return from_str(elem_itr->second); 85 | } 86 | else { 87 | throw std::runtime_error{ "Option " + option_name + " not found" }; 88 | } 89 | } 90 | 91 | 92 | bool plugin_config_t::read_conf(const PackDefaultParamStruct* dps, bool reread) 93 | { 94 | std::setlocale(LC_ALL, ""); 95 | using namespace std::literals::string_literals; 96 | if (!reread) { 97 | config_file_path.push_back(dps->DefaultIniName); 98 | auto slash_idx = config_file_path.find_last(get_path_separator()); 99 | if (slash_idx == config_file_path.npos) 100 | slash_idx = 0; 101 | config_file_path.shrink_to(slash_idx); 102 | config_file_path.push_back(inifilename); 103 | 104 | plugin_interface_version_hi = dps->PluginInterfaceVersionHi; 105 | plugin_interface_version_lo = dps->PluginInterfaceVersionLow; 106 | } 107 | 108 | std::FILE* cf = std::fopen( config_file_path.data(), "r"); 109 | if (!cf) { 110 | return false; // Use default configuration 111 | } 112 | 113 | auto res = file_to_options_map(cf); 114 | if (res) { 115 | std::fclose(cf); 116 | return false; // Wrong configuration would be overwritten by default configuration. 117 | } 118 | try { 119 | ignore_boot_signature = get_option_from_map("ignore_boot_signature"s); 120 | use_VFAT = get_option_from_map("use_VFAT"s); 121 | process_DOS1xx_images = get_option_from_map("process_DOS1xx_images"s); 122 | process_MBR = get_option_from_map("process_MBR"s); 123 | process_DOS1xx_exceptions = get_option_from_map("process_DOS1xx_exceptions"s); 124 | search_for_boot_sector = get_option_from_map("search_for_boot_sector"s); 125 | search_for_boot_sector_range = get_option_from_map("search_for_boot_sector_range"s); 126 | allow_dialogs = get_option_from_map("allow_dialogs"s); 127 | allow_txt_log = get_option_from_map("allow_txt_log"s); 128 | debug_level = get_option_from_map("debug_level"s); 129 | 130 | if (allow_txt_log && log_file_path.is_empty()) { 131 | auto tstr = get_option_from_map("log_file_path"s); 132 | log_file_path.clear(); 133 | log_file_path.push_back(tstr.data()); 134 | 135 | log_file = open_file_overwrite(log_file_path.data()); 136 | if (log_file == file_open_error_v) { 137 | allow_txt_log = false; 138 | } 139 | } 140 | } 141 | catch (std::exception& ex) { 142 | (void)ex; 143 | std::fclose(cf); 144 | return false; 145 | } 146 | 147 | std::fclose(cf); 148 | options_map = options_map_t{}; // Optimization -- options_map.clear() can leave allocated internal structures 149 | 150 | return validate_conf(); 151 | } 152 | 153 | bool plugin_config_t::validate_conf() { 154 | if (debug_level > 2) 155 | return false; 156 | return true; 157 | } 158 | 159 | bool plugin_config_t::write_conf() 160 | { 161 | assert(validate_conf() && "Inconsisten fatdiskimg plugin configuration"); 162 | 163 | std::FILE* cf = std::fopen(config_file_path.data(), "w"); 164 | 165 | //std::ofstream cf{ config_file_path.data() }; 166 | if ( !cf ) { 167 | return false; 168 | } 169 | fprintf(cf, "[FAT_disk_img_plugin]\n"); 170 | fprintf(cf, "ignore_boot_signature=%x\n", ignore_boot_signature); 171 | fprintf(cf, "use_VFAT=%x\n", use_VFAT); 172 | fprintf(cf, "process_DOS1xx_images=%x\n", process_DOS1xx_images); 173 | fprintf(cf, "process_MBR=%x\n", process_MBR); 174 | fprintf(cf, "# Highly specialized exceptions for the popular images found on the Internet:\n"); 175 | fprintf(cf, "process_DOS1xx_exceptions=%x\n", process_DOS1xx_exceptions); 176 | fprintf(cf, "# WinImage-like behavior -- if boot is not on the beginning of the file, \n"); 177 | fprintf(cf, "# # search it by the pattern 0xEB 0xXX 0x90 .... 0x55 0xAA\n"); 178 | fprintf(cf, "search_for_boot_sector=%x\n", search_for_boot_sector); 179 | fprintf(cf, "search_for_boot_sector_range=%zx\n", search_for_boot_sector_range); 180 | fprintf(cf, "allow_dialogs=%x\n", allow_dialogs); 181 | fprintf(cf, "allow_txt_log=%x\n", allow_txt_log); 182 | log_file_path.push_back("D:\\Temp\\fatimg.txt"); 183 | fprintf(cf, "log_file_path=%s\n", log_file_path.data()); 184 | fprintf(cf, "debug_level=%x\n\n", debug_level); 185 | 186 | std::fclose(cf); 187 | return true; 188 | } 189 | 190 | -------------------------------------------------------------------------------- /plugin_config.h: -------------------------------------------------------------------------------- 1 | #ifndef PLUGIN_CONFIG_H_INCLUDED 2 | #define PLUGIN_CONFIG_H_INCLUDED 3 | 4 | #include "minimal_fixed_string.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef _WIN32 11 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 12 | #ifndef NOMINMAX 13 | #define NOMINMAX 14 | #endif 15 | #include 16 | #include "sysio_winapi.h" 17 | #endif 18 | #include "wcxhead.h" 19 | 20 | 21 | struct plugin_config_t { 22 | minimal_fixed_string_t config_file_path; 23 | uint32_t plugin_interface_version_lo = 0; 24 | uint32_t plugin_interface_version_hi = 0; 25 | bool ignore_boot_signature = true; // Some historical floppy images contain correct BPB but do not have 0x55AA signature 26 | // Examples are Norton Utilities 2.00 and 2.01; CheckIt Pro v1.11 (3.5-1.44mb) 27 | #if defined FLTK_ENABLED_EXPERIMENTAL && !defined NDEBUG 28 | bool allow_dialogs = true; 29 | bool allow_txt_log = true; 30 | #else 31 | bool allow_dialogs = false; 32 | bool allow_txt_log = false; 33 | #endif 34 | minimal_fixed_string_t log_file_path; 35 | file_handle_t log_file = file_handle_t(); 36 | 37 | bool use_VFAT = true; 38 | bool process_DOS1xx_images = true; 39 | bool process_MBR = true; 40 | bool process_DOS1xx_exceptions = true; // Highly specialized exceptions for the popular images found on the Internet 41 | bool search_for_boot_sector = true; // WinImage-like behavior -- if boot is not on the beginning of the file, 42 | // search it by the pattern 0xEB 0xXX 0x90 .... 0x55 0xAA 43 | size_t search_for_boot_sector_range = 64 * 1024; 44 | 45 | //! Enum is not convenient here because of I/O 46 | static constexpr int NO_DEBUG = 0; 47 | static constexpr int DEBUGGER_MSG = 1; 48 | static constexpr int GUI_MSG = 2; 49 | int debug_level = NO_DEBUG; 50 | //------------------------------------------------------------ 51 | bool read_conf (const PackDefaultParamStruct* dps, bool reread); 52 | bool write_conf(); 53 | 54 | private: 55 | using options_map_t = std::map; 56 | 57 | int file_to_options_map(std::FILE* cf); 58 | 59 | template 60 | T get_option_from_map(const std::string& option_name) const; 61 | 62 | bool validate_conf(); 63 | 64 | options_map_t options_map; 65 | 66 | constexpr static const char* inifilename = "\\fatdiskimg.ini"; 67 | 68 | public: 69 | template 70 | void log_print(const char* format, const Args&... args) { 71 | if (allow_txt_log) { 72 | log_print_f(log_file, format, args...); 73 | } 74 | } 75 | 76 | template 77 | void log_print_dbg(const char* format, const Args&... args) { 78 | debug_print(format, args...); 79 | log_print(format, args...); 80 | } 81 | 82 | }; 83 | 84 | #endif -------------------------------------------------------------------------------- /pluginst.inf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/indrekis/FATImage_TCMD_plugin/622eaea19b42b4b09a1b5d5c1f3ab0bcad211e77/pluginst.inf -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by Script1.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1000 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /string_tools.cpp: -------------------------------------------------------------------------------- 1 | // This is a personal academic project. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 3 | /* 4 | * Copyright (c) 2017-2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 5 | * 6 | * The code is released under the MIT License. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "string_tools.h" 13 | 14 | std::string trim(std::string arg) { // Note: we need copy here -- let compiler create it for us 15 | constexpr auto is_space_priv = [](auto a) { return std::isspace(a); }; 16 | auto last_nonspace = std::find_if_not(arg.rbegin(), arg.rend(), is_space_priv ).base(); 17 | if(last_nonspace != arg.end()) 18 | arg.erase(last_nonspace, arg.end()); 19 | auto first_nonspace = std::find_if_not(arg.begin(), arg.end(), is_space_priv ); 20 | arg.erase(arg.begin(), first_nonspace); 21 | return arg; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /string_tools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 3 | * 4 | * The code is released under the MIT License. 5 | */ 6 | 7 | #ifndef TEST_STRING_TOOLS_HPP 8 | #define TEST_STRING_TOOLS_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // #define STRING_TOOLS_USE_STRINGSTREAM 16 | #ifdef STRING_TOOLS_USE_STRINGSTREAM 17 | #include 18 | #endif 19 | 20 | std::string trim(std::string arg); 21 | 22 | template 23 | auto from_str(const std::string& arg){ 24 | T res = {}; 25 | size_t last_sym = 0; 26 | if constexpr (std::is_same_v) { 27 | res = std::stoull(arg, &last_sym); 28 | } 29 | else if constexpr (std::is_same_v) { 30 | res = static_cast(std::stoi(arg, &last_sym)); 31 | } 32 | else if constexpr (std::is_same_v) { 33 | res = std::stoi(arg, &last_sym); 34 | } 35 | else if constexpr (std::is_same_v>) { 36 | return arg; 37 | } 38 | else { 39 | #if defined STRING_TOOLS_USE_STRINGSTREAM 40 | //! Slow but universal 41 | T res = T{}; 42 | std::stringstream ss{ arg }; 43 | ss >> res; 44 | if (std::string temp; ss >> temp) { 45 | throw std::runtime_error{ "Wrong numerical value: " + arg }; 46 | } 47 | return res; 48 | #else 49 | assert(false && "Not implemented"); // Get rid of stringstream 50 | #endif 51 | } 52 | 53 | if (last_sym != arg.size()) { 54 | throw std::runtime_error{ "Wrong numerical value: " + arg }; 55 | } 56 | 57 | return res; 58 | } 59 | 60 | #endif //TEST_STRING_TOOLS_HPP 61 | -------------------------------------------------------------------------------- /sysio_winapi.cpp: -------------------------------------------------------------------------------- 1 | // This is a personal academic project. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 3 | /* 4 | * Floppy disk images unpack plugin for the Total Commander. 5 | * Copyright (c) 2002, IvGzury ( ivgzury@hotmail.com ) 6 | * Copyright (c) 2022, Oleg Farenyuk aka Indrekis ( indrekis@gmail.com ) 7 | * 8 | * Oleg Farenyuk's code is released under the MIT License. 9 | * 10 | * Original IvGzury copyright message: 11 | * This program is absolutely free software. 12 | * If you have any remarks or problems, please don't 13 | * hesitate to send me an email. 14 | */ 15 | #include "sysio_winapi.h" 16 | 17 | file_handle_t open_file_shared_read(const char* filename) { 18 | file_handle_t handle; 19 | handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); 20 | return handle; 21 | } 22 | 23 | file_handle_t open_file_write(const char* filename) { 24 | file_handle_t handle; 25 | handle = CreateFile(filename, GENERIC_WRITE | FILE_APPEND_DATA, FILE_SHARE_READ, 0, CREATE_NEW, 0, 0); 26 | return handle; 27 | } 28 | 29 | file_handle_t open_file_overwrite(const char* filename) { 30 | file_handle_t handle; 31 | handle = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); 32 | return handle; 33 | } 34 | 35 | //! Returns true if success 36 | bool close_file(file_handle_t handle) { 37 | return CloseHandle(handle); 38 | } 39 | 40 | bool flush_file(file_handle_t handle) { 41 | return FlushFileBuffers(handle); 42 | } 43 | 44 | bool delete_file(const char* filename) { 45 | return DeleteFile(filename); 46 | } 47 | 48 | bool get_temp_filename(char* buff, const char prefix[]) { 49 | char dest_path[MAX_PATH]; 50 | auto dwRetVal = GetTempPath(MAX_PATH, // length of the buffer 51 | dest_path); // buffer for path 52 | if (dwRetVal > MAX_PATH || (dwRetVal == 0)) 53 | { 54 | return false; 55 | } 56 | dwRetVal = GetTempFileName(dest_path, // directory for tmp files 57 | prefix, // temp file name prefix -- 3 bytes used only 58 | 0, // create unique name 59 | buff); // buffer for name 60 | if (dwRetVal == 0) { 61 | return false; 62 | } 63 | return true; 64 | } 65 | 66 | //! Returns true if success 67 | bool set_file_pointer(file_handle_t handle, size_t offset) { 68 | LARGE_INTEGER offs; 69 | offs.QuadPart = offset; 70 | return SetFilePointerEx(handle, offs, nullptr, FILE_BEGIN); 71 | } 72 | 73 | size_t read_file(file_handle_t handle, void* buffer_ptr, size_t size) { 74 | bool res; 75 | DWORD result = 0; 76 | res = ReadFile(handle, buffer_ptr, static_cast(size), &result, nullptr); //-V2001 77 | if (!res) { 78 | return static_cast(-1); 79 | } 80 | else { 81 | return static_cast(result); 82 | } 83 | } 84 | 85 | size_t write_file(file_handle_t handle, const void* buffer_ptr, size_t size) { 86 | bool res; 87 | DWORD result = 0; 88 | res = WriteFile(handle, buffer_ptr, static_cast(size), &result, nullptr); //-V2001 89 | if (!res) { 90 | return static_cast(-1); 91 | } 92 | else { 93 | return static_cast(result); 94 | } 95 | } 96 | 97 | bool set_file_datetime(file_handle_t handle, uint32_t file_datetime) 98 | { 99 | FILETIME LocTime, GlobTime; 100 | DosDateTimeToFileTime(static_cast(file_datetime >> 16), 101 | static_cast(file_datetime & static_cast(0xFFFF)), 102 | &LocTime); 103 | LocalFileTimeToFileTime(&LocTime, &GlobTime); 104 | SetFileTime(handle, nullptr, nullptr, &GlobTime); 105 | return true; // TODO: Add error handling 106 | } 107 | 108 | bool set_file_attributes(const char* filename, uint32_t attribute){ 109 | return SetFileAttributes(filename, attribute); 110 | } 111 | 112 | size_t get_file_size(const char* filename) 113 | { 114 | WIN32_FILE_ATTRIBUTE_DATA fad; 115 | if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad)) 116 | return -1; 117 | LARGE_INTEGER size; 118 | size.HighPart = fad.nFileSizeHigh; 119 | size.LowPart = fad.nFileSizeLow; 120 | return size.QuadPart; 121 | } 122 | 123 | size_t get_file_size(file_handle_t handle) 124 | { 125 | LARGE_INTEGER size; 126 | if (!GetFileSizeEx(handle, &size)) 127 | return -1; 128 | 129 | return size.QuadPart; 130 | } 131 | 132 | uint32_t get_current_datetime() 133 | { 134 | SYSTEMTIME t = {0}; 135 | FILETIME ft = { 0 }; 136 | uint16_t dft[2] = { 0 }; 137 | GetSystemTime(&t); 138 | SystemTimeToFileTime(&t, &ft); 139 | FileTimeToDosDateTime(&ft, dft+1, dft); 140 | return (static_cast(dft[1]) << 16) + dft[0]; 141 | } 142 | 143 | char simple_ucs16_to_local(wchar_t wc) { 144 | char tc = '\0'; 145 | WideCharToMultiByte(CP_ACP, 0, &wc, -1, &tc, 1, NULL, NULL); 146 | return tc; 147 | } 148 | 149 | int ucs16_to_local(char* outstr, const wchar_t* instr, size_t maxoutlen) { 150 | if (instr != nullptr) { 151 | // CP_ACP The system default Windows ANSI code page. 152 | // TODO: error analysis 153 | int res = WideCharToMultiByte(CP_ACP, 0, instr, static_cast(maxoutlen), 154 | outstr, static_cast(maxoutlen), NULL, NULL); 155 | if (res != 0) 156 | return 0; 157 | else 158 | return GetLastError(); 159 | } 160 | else { 161 | return 1; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /sysio_winapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef SYSIO_WINAPI_H_INCLUDED 4 | #define SYSIO_WINAPI_H_INCLUDED 5 | 6 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 7 | #ifndef NOMINMAX 8 | #define NOMINMAX 9 | #endif 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #ifndef NDEBUG 17 | #include 18 | #endif 19 | 20 | const auto file_open_error_v = INVALID_HANDLE_VALUE; 21 | using file_handle_t = HANDLE; 22 | 23 | // All functions returning bool returns true on success 24 | file_handle_t open_file_shared_read(const char* filename); 25 | file_handle_t open_file_write(const char* filename); 26 | file_handle_t open_file_overwrite(const char* filename); 27 | bool close_file(file_handle_t handle); 28 | bool flush_file(file_handle_t handle); 29 | bool delete_file(const char* filename); 30 | bool get_temp_filename(char* buff, const char prefix[]); 31 | bool set_file_pointer(file_handle_t handle, size_t offset); 32 | size_t read_file(file_handle_t handle, void* buffer_ptr, size_t size); 33 | size_t write_file(file_handle_t handle, const void* buffer_ptr, size_t size); 34 | bool set_file_datetime(file_handle_t handle, uint32_t file_datetime); 35 | bool set_file_attributes(const char* filename, uint32_t attribute); 36 | size_t get_file_size(const char* filename); 37 | size_t get_file_size(file_handle_t handle); 38 | inline char get_path_separator() { return '\\'; } 39 | 40 | uint32_t get_current_datetime(); 41 | 42 | //! Very basic, simplistic, function 43 | char simple_ucs16_to_local(wchar_t wc); 44 | //! More advenced: 45 | int ucs16_to_local(char* outstr, const wchar_t* instr, size_t maxoutlen); 46 | 47 | // Defect report: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2905r2.html disables forwarding and Args&& 48 | template 49 | void debug_print(const char* format, const Args&... args) { 50 | #ifndef NDEBUG 51 | try { 52 | std::string strbuf = std::vformat(format, std::make_format_args(args...)); 53 | OutputDebugString(strbuf.c_str()); // Sends a string to the debugger 54 | } 55 | catch (std::exception& ex) { 56 | OutputDebugString(ex.what()); 57 | } 58 | // See also http://www.nirsoft.net/utils/simple_program_debugger.html 59 | #endif // !NDEBUG 60 | } 61 | 62 | template 63 | void log_print_f(file_handle_t hnd, const char* format, const Args&... args) { 64 | try { 65 | char strbuf[1024 * 4]; //-V112 66 | auto res = snprintf(strbuf, sizeof(strbuf) - 1, format, args...); 67 | strcat(strbuf, "\n"); 68 | write_file(hnd, strbuf, strlen(strbuf)); 69 | flush_file(hnd); 70 | } 71 | catch (std::exception& ex) { 72 | OutputDebugString(ex.what()); 73 | } 74 | } 75 | 76 | 77 | #endif 78 | 79 | 80 | -------------------------------------------------------------------------------- /wcxhead.h: -------------------------------------------------------------------------------- 1 | #ifndef _WCXHEAD_H_ 2 | #define _WCXHEAD_H_ 3 | /* Contents of file wcxhead.h */ 4 | /* It contains definitions of error codes, flags and callbacks */ 5 | 6 | /* Error codes returned to calling application */ 7 | #define E_END_ARCHIVE 10 /* No more files in archive */ 8 | #define E_NO_MEMORY 11 /* Not enough memory */ 9 | #define E_BAD_DATA 12 /* CRC error in the data of the currently unpacked file */ 10 | #define E_BAD_ARCHIVE 13 /* The archive as a whole is bad, e.g. damaged headers */ 11 | #define E_UNKNOWN_FORMAT 14 /* Archive format unknown */ 12 | #define E_EOPEN 15 /* Cannot open existing file */ 13 | #define E_ECREATE 16 /* Cannot create file */ 14 | #define E_ECLOSE 17 /* Error closing file */ 15 | #define E_EREAD 18 /* Error reading from file */ 16 | #define E_EWRITE 19 /* Error writing to file */ 17 | #define E_SMALL_BUF 20 /* Buffer too small */ 18 | #define E_EABORTED 21 /* Function aborted by user */ 19 | #define E_NO_FILES 22 /* No files found */ 20 | #define E_TOO_MANY_FILES 23 /* Too many files to pack */ 21 | #define E_NOT_SUPPORTED 24 /* Function not supported */ 22 | 23 | /* flags for unpacking */ 24 | #define PK_OM_LIST 0 25 | #define PK_OM_EXTRACT 1 26 | 27 | /* flags for ProcessFile */ 28 | #define PK_SKIP 0 /* Skip this file */ 29 | #define PK_TEST 1 /* Test file integrity */ 30 | #define PK_EXTRACT 2 /* Extract to disk */ 31 | 32 | /* Flags passed through ChangeVolProc */ 33 | #define PK_VOL_ASK 0 /* Ask user for location of next volume */ 34 | #define PK_VOL_NOTIFY 1 /* Notify app that next volume will be unpacked */ 35 | 36 | /* Flags for packing */ 37 | 38 | /* For PackFiles */ 39 | #define PK_PACK_MOVE_FILES 1 /* Delete original after packing */ 40 | #define PK_PACK_SAVE_PATHS 2 /* Save path names of files */ 41 | #define PK_PACK_ENCRYPT 4 /* Ask user for password, then encrypt */ 42 | 43 | /* Returned by GetPackCaps */ 44 | #define PK_CAPS_NEW 1 /* Can create new archives */ 45 | #define PK_CAPS_MODIFY 2 /* Can modify exisiting archives */ 46 | #define PK_CAPS_MULTIPLE 4 /* Archive can contain multiple files */ 47 | #define PK_CAPS_DELETE 8 /* Can delete files */ 48 | #define PK_CAPS_OPTIONS 16 /* Has options dialog */ 49 | #define PK_CAPS_MEMPACK 32 /* Supports packing in memory */ 50 | #define PK_CAPS_BY_CONTENT 64 /* Detect archive type by content */ 51 | #define PK_CAPS_SEARCHTEXT 128 /* Allow searching for text in archives */ 52 | /* created with this plugin} */ 53 | #define PK_CAPS_HIDE 256 /* Show as normal files (hide packer */ 54 | /* icon), open with Ctrl+PgDn, not Enter*/ 55 | #define PK_CAPS_ENCRYPT 512 /* Plugin supports PK_PACK_ENCRYPT option*/ 56 | 57 | #define BACKGROUND_UNPACK 1 /* Which operations are thread-safe? */ 58 | #define BACKGROUND_PACK 2 59 | #define BACKGROUND_MEMPACK 4 60 | 61 | /* Flags for packing in memory */ 62 | #define MEM_OPTIONS_WANTHEADERS 1 /* Return archive headers with packed data */ 63 | 64 | /* Errors returned by PackToMem */ 65 | #define MEMPACK_OK 0 /* Function call finished OK, but there is more data */ 66 | #define MEMPACK_DONE 1 /* Function call finished OK, there is no more data */ 67 | 68 | #define PK_CRYPT_SAVE_PASSWORD 1 69 | #define PK_CRYPT_LOAD_PASSWORD 2 70 | #define PK_CRYPT_LOAD_PASSWORD_NO_UI 3 // Load password only if master password has already been entered! 71 | #define PK_CRYPT_COPY_PASSWORD 4 // Copy encrypted password to new archive name 72 | #define PK_CRYPT_MOVE_PASSWORD 5 // Move password when renaming an archive 73 | #define PK_CRYPT_DELETE_PASSWORD 6 // Delete password 74 | 75 | #define PK_CRYPTOPT_MASTERPASS_SET 1 // The user already has a master password defined 76 | 77 | typedef struct { 78 | char ArcName[260]; 79 | char FileName[260]; 80 | int Flags; 81 | int PackSize; 82 | int UnpSize; 83 | int HostOS; 84 | int FileCRC; 85 | int FileTime; 86 | int UnpVer; 87 | int Method; 88 | int FileAttr; 89 | char* CmtBuf; 90 | int CmtBufSize; 91 | int CmtSize; 92 | int CmtState; 93 | } tHeaderData; 94 | 95 | typedef struct { 96 | char ArcName[1024]; 97 | char FileName[1024]; 98 | int Flags; 99 | unsigned int PackSize; 100 | unsigned int PackSizeHigh; 101 | unsigned int UnpSize; 102 | unsigned int UnpSizeHigh; 103 | int HostOS; 104 | int FileCRC; 105 | int FileTime; 106 | int UnpVer; 107 | int Method; 108 | int FileAttr; 109 | char* CmtBuf; 110 | int CmtBufSize; 111 | int CmtSize; 112 | int CmtState; 113 | char Reserved[1024]; 114 | } tHeaderDataEx; 115 | 116 | typedef struct { 117 | WCHAR ArcName[1024]; 118 | WCHAR FileName[1024]; 119 | int Flags; 120 | unsigned int PackSize; 121 | unsigned int PackSizeHigh; 122 | unsigned int UnpSize; 123 | unsigned int UnpSizeHigh; 124 | int HostOS; 125 | int FileCRC; 126 | int FileTime; 127 | int UnpVer; 128 | int Method; 129 | int FileAttr; 130 | char* CmtBuf; 131 | int CmtBufSize; 132 | int CmtSize; 133 | int CmtState; 134 | char Reserved[1024]; 135 | } tHeaderDataExW; 136 | 137 | typedef struct { 138 | char* ArcName; 139 | int OpenMode; 140 | int OpenResult; 141 | char* CmtBuf; 142 | int CmtBufSize; 143 | int CmtSize; 144 | int CmtState; 145 | } tOpenArchiveData; 146 | 147 | typedef struct { 148 | WCHAR* ArcName; 149 | int OpenMode; 150 | int OpenResult; 151 | WCHAR* CmtBuf; 152 | int CmtBufSize; 153 | int CmtSize; 154 | int CmtState; 155 | } tOpenArchiveDataW; 156 | 157 | typedef struct { 158 | int size; 159 | DWORD PluginInterfaceVersionLow; 160 | DWORD PluginInterfaceVersionHi; 161 | char DefaultIniName[MAX_PATH]; 162 | } PackDefaultParamStruct; 163 | 164 | /* Definition of callback functions called by the DLL 165 | Ask to swap disk for multi-volume archive */ 166 | typedef int(__stdcall* tChangeVolProc)(char* ArcName, int Mode); 167 | typedef int(__stdcall* tChangeVolProcW)(WCHAR* ArcName, int Mode); 168 | /* Notify that data is processed - used for progress dialog */ 169 | typedef int(__stdcall* tProcessDataProc)(char* FileName, int Size); 170 | typedef int(__stdcall* tProcessDataProcW)(WCHAR* FileName, int Size); 171 | typedef int(__stdcall* tPkCryptProc)(int CryptoNr, int Mode, 172 | char* ArchiveName, char* Password, int maxlen); 173 | typedef int(__stdcall* tPkCryptProcW)(int CryptoNr, int Mode, 174 | WCHAR* ArchiveName, WCHAR* Password, int maxlen); 175 | 176 | #endif --------------------------------------------------------------------------------