@@ -96,6 +96,21 @@ private static int Main(string[] args)
9696 {
9797 return RunImageSpec ( args , 1 ) ;
9898 }
99+ else if ( args . Length > 0 && ( string . Equals ( args [ 0 ] , "compress" , StringComparison . OrdinalIgnoreCase ) ||
100+ string . Equals ( args [ 0 ] , "cso" , StringComparison . OrdinalIgnoreCase ) ) )
101+ {
102+ return RunCompressMode ( args , 1 ) ;
103+ }
104+ else if ( args . Length > 0 && ( string . Equals ( args [ 0 ] , "decompress" , StringComparison . OrdinalIgnoreCase ) ||
105+ string . Equals ( args [ 0 ] , "uncso" , StringComparison . OrdinalIgnoreCase ) ||
106+ string . Equals ( args [ 0 ] , "decso" , StringComparison . OrdinalIgnoreCase ) ) )
107+ {
108+ return RunDecompressMode ( args , 1 ) ;
109+ }
110+ else if ( args . Length > 0 && string . Equals ( args [ 0 ] , "checksum" , StringComparison . OrdinalIgnoreCase ) )
111+ {
112+ return RunChecksumMode ( args , 1 ) ;
113+ }
99114
100115 for ( var i = optind ; i < args . Length ; i ++ )
101116 {
@@ -1670,6 +1685,249 @@ private static int RunImageSpec(string[] args, int optind)
16701685 return 0 ;
16711686 }
16721687
1688+ private static int RunCompressMode ( string [ ] args , int optind )
1689+ {
1690+ string ? output = null ;
1691+ int level = 9 ;
1692+ long ? splitBytes = null ;
1693+ var positionals = new List < string > ( ) ;
1694+
1695+ for ( int i = optind ; i < args . Length ; i ++ )
1696+ {
1697+ var a = args [ i ] ;
1698+ if ( string . Equals ( a , "-o" , StringComparison . OrdinalIgnoreCase ) ||
1699+ string . Equals ( a , "--output" , StringComparison . OrdinalIgnoreCase ) )
1700+ {
1701+ if ( i + 1 >= args . Length )
1702+ {
1703+ Logger . LogErr ( "Error: -o requires a filename\n " ) ;
1704+ return 1 ;
1705+ }
1706+ output = args [ ++ i ] ;
1707+ }
1708+ else if ( string . Equals ( a , "--ciso-level" , StringComparison . OrdinalIgnoreCase ) ||
1709+ string . Equals ( a , "-l" , StringComparison . OrdinalIgnoreCase ) ||
1710+ string . Equals ( a , "--level" , StringComparison . OrdinalIgnoreCase ) )
1711+ {
1712+ if ( i + 1 >= args . Length || ! int . TryParse ( args [ i + 1 ] , out level ) || level < 0 || level > 9 )
1713+ {
1714+ Logger . LogErr ( "Error: --ciso-level requires an integer 0..9\n " ) ;
1715+ return 1 ;
1716+ }
1717+ i ++ ;
1718+ }
1719+ else if ( string . Equals ( a , "--ciso-split" , StringComparison . OrdinalIgnoreCase ) ||
1720+ string . Equals ( a , "--split" , StringComparison . OrdinalIgnoreCase ) )
1721+ {
1722+ if ( i + 1 >= args . Length || ! long . TryParse ( args [ i + 1 ] , out var sb ) || sb <= 0 )
1723+ {
1724+ Logger . LogErr ( "Error: --ciso-split requires a positive integer (bytes)\n " ) ;
1725+ return 1 ;
1726+ }
1727+ splitBytes = sb ;
1728+ i ++ ;
1729+ }
1730+ else if ( string . Equals ( a , "-q" , StringComparison . OrdinalIgnoreCase ) )
1731+ {
1732+ Logger . Quiet = true ;
1733+ }
1734+ else if ( string . Equals ( a , "-Q" , StringComparison . OrdinalIgnoreCase ) )
1735+ {
1736+ Logger . Quiet = Logger . RealQuiet = true ;
1737+ }
1738+ else if ( string . Equals ( a , "-h" , StringComparison . OrdinalIgnoreCase ) ||
1739+ string . Equals ( a , "--help" , StringComparison . OrdinalIgnoreCase ) )
1740+ {
1741+ PrintUsage ( ) ;
1742+ return 0 ;
1743+ }
1744+ else if ( string . Equals ( a , "-v" , StringComparison . OrdinalIgnoreCase ) ||
1745+ string . Equals ( a , "--version" , StringComparison . OrdinalIgnoreCase ) )
1746+ {
1747+ Console . Write ( Constants . Banner ) ;
1748+ return 0 ;
1749+ }
1750+ else if ( a . StartsWith ( '-' ) )
1751+ {
1752+ Logger . LogErr ( $ "Error: unknown option for compress: { a } \n ") ;
1753+ PrintUsage ( ) ;
1754+ return 1 ;
1755+ }
1756+ else
1757+ {
1758+ positionals . Add ( a ) ;
1759+ }
1760+ }
1761+
1762+ if ( positionals . Count < 1 || positionals . Count > 2 )
1763+ {
1764+ Logger . LogErr ( "Error: compress requires <source> [output.cso]\n " ) ;
1765+ PrintUsage ( ) ;
1766+ return 1 ;
1767+ }
1768+
1769+ string source = positionals [ 0 ] ;
1770+ string ? outCso = positionals . Count == 2 ? positionals [ 1 ] : output ;
1771+
1772+ try
1773+ {
1774+ Logger . Log ( Constants . Banner ) ;
1775+ int rc = CisoWriter . CompressToCso ( source , outCso , level , splitBytes ) ;
1776+ return rc ;
1777+ }
1778+ catch ( Exception ex )
1779+ {
1780+ Logger . LogErr ( $ "Error compressing: { ex . Message } \n ") ;
1781+ return 1 ;
1782+ }
1783+ }
1784+
1785+ private static int RunDecompressMode ( string [ ] args , int optind )
1786+ {
1787+ string ? output = null ;
1788+ var positionals = new List < string > ( ) ;
1789+
1790+ for ( int i = optind ; i < args . Length ; i ++ )
1791+ {
1792+ var a = args [ i ] ;
1793+ if ( string . Equals ( a , "-o" , StringComparison . OrdinalIgnoreCase ) ||
1794+ string . Equals ( a , "--output" , StringComparison . OrdinalIgnoreCase ) )
1795+ {
1796+ if ( i + 1 >= args . Length )
1797+ {
1798+ Logger . LogErr ( "Error: -o requires a filename\n " ) ;
1799+ return 1 ;
1800+ }
1801+ output = args [ ++ i ] ;
1802+ }
1803+ else if ( string . Equals ( a , "-q" , StringComparison . OrdinalIgnoreCase ) )
1804+ {
1805+ Logger . Quiet = true ;
1806+ }
1807+ else if ( string . Equals ( a , "-Q" , StringComparison . OrdinalIgnoreCase ) )
1808+ {
1809+ Logger . Quiet = Logger . RealQuiet = true ;
1810+ }
1811+ else if ( string . Equals ( a , "-h" , StringComparison . OrdinalIgnoreCase ) ||
1812+ string . Equals ( a , "--help" , StringComparison . OrdinalIgnoreCase ) )
1813+ {
1814+ PrintUsage ( ) ;
1815+ return 0 ;
1816+ }
1817+ else if ( string . Equals ( a , "-v" , StringComparison . OrdinalIgnoreCase ) ||
1818+ string . Equals ( a , "--version" , StringComparison . OrdinalIgnoreCase ) )
1819+ {
1820+ Console . Write ( Constants . Banner ) ;
1821+ return 0 ;
1822+ }
1823+ else if ( a . StartsWith ( '-' ) )
1824+ {
1825+ Logger . LogErr ( $ "Error: unknown option for decompress: { a } \n ") ;
1826+ PrintUsage ( ) ;
1827+ return 1 ;
1828+ }
1829+ else
1830+ {
1831+ positionals . Add ( a ) ;
1832+ }
1833+ }
1834+
1835+ if ( positionals . Count < 1 || positionals . Count > 2 )
1836+ {
1837+ Logger . LogErr ( "Error: decompress requires <cso> [output.iso]\n " ) ;
1838+ PrintUsage ( ) ;
1839+ return 1 ;
1840+ }
1841+
1842+ string source = positionals [ 0 ] ;
1843+ string ? outIso = positionals . Count == 2 ? positionals [ 1 ] : output ;
1844+
1845+ try
1846+ {
1847+ Logger . Log ( Constants . Banner ) ;
1848+ int rc = CisoReader . DecompressToIso ( source , outIso ) ;
1849+ return rc ;
1850+ }
1851+ catch ( Exception ex )
1852+ {
1853+ Logger . LogErr ( $ "Error decompressing: { ex . Message } \n ") ;
1854+ return 1 ;
1855+ }
1856+ }
1857+
1858+ private static int RunChecksumMode ( string [ ] args , int optind )
1859+ {
1860+ bool silent = false ;
1861+ var positionals = new List < string > ( ) ;
1862+
1863+ for ( int i = optind ; i < args . Length ; i ++ )
1864+ {
1865+ var a = args [ i ] ;
1866+ if ( string . Equals ( a , "--silent" , StringComparison . OrdinalIgnoreCase ) ||
1867+ string . Equals ( a , "-s" , StringComparison . OrdinalIgnoreCase ) )
1868+ {
1869+ silent = true ;
1870+ }
1871+ else if ( string . Equals ( a , "-q" , StringComparison . OrdinalIgnoreCase ) )
1872+ {
1873+ Logger . Quiet = true ;
1874+ }
1875+ else if ( string . Equals ( a , "-Q" , StringComparison . OrdinalIgnoreCase ) )
1876+ {
1877+ Logger . Quiet = Logger . RealQuiet = true ;
1878+ }
1879+ else if ( string . Equals ( a , "-h" , StringComparison . OrdinalIgnoreCase ) ||
1880+ string . Equals ( a , "--help" , StringComparison . OrdinalIgnoreCase ) )
1881+ {
1882+ PrintUsage ( ) ;
1883+ return 0 ;
1884+ }
1885+ else if ( string . Equals ( a , "-v" , StringComparison . OrdinalIgnoreCase ) ||
1886+ string . Equals ( a , "--version" , StringComparison . OrdinalIgnoreCase ) )
1887+ {
1888+ Console . Write ( Constants . Banner ) ;
1889+ return 0 ;
1890+ }
1891+ else if ( a . StartsWith ( '-' ) )
1892+ {
1893+ Logger . LogErr ( $ "Error: unknown option for checksum: { a } \n ") ;
1894+ PrintUsage ( ) ;
1895+ return 1 ;
1896+ }
1897+ else
1898+ {
1899+ positionals . Add ( a ) ;
1900+ }
1901+ }
1902+
1903+ if ( positionals . Count == 0 )
1904+ {
1905+ Logger . LogErr ( "Error: checksum requires at least one image\n " ) ;
1906+ PrintUsage ( ) ;
1907+ return 1 ;
1908+ }
1909+
1910+ int exit = 0 ;
1911+ foreach ( var iso in positionals )
1912+ {
1913+ try
1914+ {
1915+ byte [ ] hash = XisoChecksum . ComputeImageChecksum ( iso ) ;
1916+ string hex = Convert . ToHexString ( hash ) . ToLowerInvariant ( ) ;
1917+ if ( silent )
1918+ Logger . Log ( $ "{ hex } \n ") ;
1919+ else
1920+ Logger . Log ( $ "{ hex } \t { iso } \n ") ;
1921+ }
1922+ catch ( Exception ex )
1923+ {
1924+ Logger . LogErr ( $ "Error checksumming { iso } : { ex . Message } \n ") ;
1925+ exit = 1 ;
1926+ }
1927+ }
1928+ return exit ;
1929+ }
1930+
16731931 private static string DeriveRedumpPath ( string xisoPath )
16741932 {
16751933 string dir = Path . GetDirectoryName ( xisoPath ) ?? "" ;
@@ -2336,6 +2594,18 @@ security sectors (--security-sectors).
23362594 --compress <iso> Alias: --petrify --update --video --zar
23372595 --security-sectors <sectors.txt> Override security sector ranges (start-end, 4096 sectors).
23382596
2597+ CISO / Compression modes:
2598+
2599+ compress <sourceDir|image.iso> [output.cso] [--ciso-level 0..9] [--ciso-split bytes]
2600+ Pack and compress to CISO (CSO). Source may be a directory (packed then compressed)
2601+ or an existing ISO. Level 0=store, 1=fastest … 9=smallest. Default 9.
2602+ Deflate per 2048-byte sector (version 1, BCL) with LZ4 read compat.
2603+ Alias: cso. Split threshold is reserved (single-file now).
2604+ decompress <cso> [output.iso] Decompress CISO/CSO to ISO (handles DEFLATE v1 and LZ4 v2).
2605+ Aliases: uncso, decso.
2606+ checksum <image> [images...] [--silent] Compute SHA3-256 image checksum (xdvdfs-compatible:
2607+ SHA3-256 over sorted path bytes + file data). Output: hex tab path.
2608+
23392609 XDVDFS / Packing modes (ordered remapping):
23402610
23412611 build-image [sourceDir] [output.iso] -f <xdvdfs.toml> -m "hostGlob:imagePath" [-O output] [-D|--dry-run]
0 commit comments