11using System ;
2+ using System . Text ;
23using System . Text . RegularExpressions ;
34using BinaryObjectScanner . Interfaces ;
45using SabreTools . Data . Models . ISO9660 ;
@@ -56,8 +57,8 @@ public class AlphaROM : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExecu
5657 if ( diskImage . VolumeDescriptorSet [ 0 ] is not PrimaryVolumeDescriptor pvd )
5758 return null ;
5859
59- // Alpharom disc check #1: disc has varying (but observed to at least always be larger than 14) length
60- // string made up of numbers and capital letters.
60+ // Disc has varying (but observed to at least always be larger than 14) length
61+ // application identifier string made up of numbers and capital letters.
6162 // TODO: triple-check that length is never below 14
6263 int offset = 0 ;
6364 var applicationIdentifierString = pvd . ApplicationIdentifier . ReadNullTerminatedAnsiString ( ref offset ) ? . Trim ( ) ;
@@ -67,27 +68,49 @@ public class AlphaROM : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExecu
6768 if ( ! Regex . IsMatch ( applicationIdentifierString , "^[A-Z0-9]*$" ) )
6869 return null ;
6970
70- // Alpharom disc check #2: disc has publisher identifier filled with varying amount of data (26-50 bytes
71- // have been observed) followed by spaces. There's a decent chance this is just a Japanese text string, but
72- // UTF, Shift-JIS, and EUC-JP all fail to display anything but garbage.
73-
74- var publisherIdentifier = pvd . PublisherIdentifier ;
75- int firstSpace = Array . FindIndex ( publisherIdentifier , b => b == 0x20 ) ;
76- if ( firstSpace <= 10 || firstSpace >= 120 )
77- return null ;
78-
79- var publisherData = new byte [ firstSpace ] ;
80- var publisherSpaces = new byte [ publisherData . Length - firstSpace ] ;
81- Array . Copy ( publisherIdentifier , 0 , publisherData , 0 , firstSpace ) ;
82- Array . Copy ( publisherIdentifier , firstSpace , publisherSpaces , 0 , publisherData . Length - firstSpace ) ;
83-
84- if ( ! Array . TrueForAll ( publisherSpaces , b => b == 0x20 ) )
85- return null ;
86-
87- if ( ! FileType . ISO9660 . IsPureData ( publisherData ) )
88- return null ;
71+ // While some alpharom discs have data in the publisher identifier that can be checked, not all of them do,
72+ // so that can't reliably be used. There are two formats currently observed regarding the application
73+ // identifier strings.
74+ // #1 examples: DCOBG11C1B094961XN, DCXA9083CA554846GP, RCXA1107UD2510461A
75+ // #2 examples: 2003120514103077LAHD, 20040326195254AVKC, 20051019163346WXUDCD
76+
77+ var applicationIdentifierStringBytes = Encoding . ASCII . GetBytes ( applicationIdentifierString ) ;
78+
79+ // Type #1: 18 characters long, mix of letters and numbers. Since the string has already been confirmed
80+ // to only consist of capital letters and numbers, a basic byte value check can be performed to ensure
81+ // at least 5 bytes are numbers and 5 bytes are letters. Unfortunately, there doesn't seem to be quite
82+ // enough of a pattern to have a better check than this, but it works well enough.
83+ if ( applicationIdentifierString . Length == 18
84+ && Array . FindAll ( applicationIdentifierStringBytes , b => b < 60 ) . Length >= 5
85+ && Array . FindAll ( applicationIdentifierStringBytes , b => b > 60 ) . Length >= 5 )
86+ {
87+ return "AlphaROM" ;
88+ }
89+
90+ // Type #2: Usually 20 characters long, but Redump ID 124334 is 18 characters long. Validate that it
91+ // starts with YYYYMMDD, followed by 6-8 more numbers, followed by letters.
92+ if ( applicationIdentifierString . Length >= 18 && applicationIdentifierString . Length <= 20 )
93+ {
94+ if ( Int32 . TryParse ( applicationIdentifierString . Substring ( 0 , 4 ) , out int year ) == false
95+ || Int32 . TryParse ( applicationIdentifierString . Substring ( 4 , 2 ) , out int month ) == false
96+ || Int32 . TryParse ( applicationIdentifierString . Substring ( 6 , 2 ) , out int day ) == false
97+ || Int32 . TryParse ( applicationIdentifierString . Substring ( 8 , 6 ) , out int extraTime ) == false )
98+ {
99+ return null ;
100+ }
101+
102+ if ( year >= 2009 || year < 2000 || month > 12 || day > 31 )
103+ return null ;
104+
105+ int index = Array . FindIndex ( applicationIdentifierStringBytes , b => b > 60 ) ;
106+
107+ var startingNumbers = Encoding . ASCII . GetBytes ( applicationIdentifierString . Substring ( 0 , index ) ) ;
108+ var finalCharacters = Encoding . ASCII . GetBytes ( applicationIdentifierString . Substring ( index ) ) ;
109+ if ( Array . TrueForAll ( startingNumbers , b => b < 60 ) && Array . TrueForAll ( finalCharacters , b => b > 60 ) )
110+ return "AlphaROM" ;
111+ }
89112
90- return "AlphaROM" ;
113+ return null ;
91114 }
92115
93116 /// <inheritdoc/>
0 commit comments