@@ -107,6 +107,10 @@ internal sealed class Database
107107 private readonly int _stringSectionNumOffsets ;
108108 /// <summary>The number of bytes in the strings table of the database.</summary>
109109 private readonly int _stringTableNumBytes ;
110+ /// <summary>Whether or not to read the number section as 32-bit integers.</summary>
111+ private readonly bool _readAs32Bit ;
112+ /// <summary>The size of the integers on the number section.</summary>
113+ private readonly int _sizeOfInt ;
110114
111115 /// <summary>Extended / user-defined entries in the terminfo database.</summary>
112116 private readonly Dictionary < string , string > _extendedStrings ;
@@ -119,11 +123,14 @@ private Database(string term, byte[] data)
119123 _term = term ;
120124 _data = data ;
121125
122- // See "man term" for the file format.
123- if ( ReadInt16 ( data , 0 ) != 0x11A ) // magic number octal 0432
124- {
125- throw new InvalidOperationException ( SR . IO_TermInfoInvalid ) ;
126- }
126+ const int MagicLegacyNumber = 0x11A ; // magic number octal 0432 for legacy ncurses terminfo
127+ const int Magic32BitNumber = 0x21E ; // magic number octal 01036 for new ncruses terminfo
128+ short magic = ReadInt16 ( data , 0 ) ;
129+ _readAs32Bit =
130+ magic == MagicLegacyNumber ? false :
131+ magic == Magic32BitNumber ? true :
132+ throw new InvalidOperationException ( SR . Format ( SR . IO_TermInfoInvalidMagicNumber , String . Concat ( "O" + Convert . ToString ( magic , 8 ) ) ) ) ; // magic number was not recognized. Printing the magic number in octal.
133+ _sizeOfInt = ( _readAs32Bit ) ? 4 : 2 ;
127134
128135 _nameSectionNumBytes = ReadInt16 ( data , 2 ) ;
129136 _boolSectionNumBytes = ReadInt16 ( data , 4 ) ;
@@ -147,7 +154,7 @@ private Database(string term, byte[] data)
147154 // (Note that the extended section also includes other Booleans and numbers, but we don't
148155 // have any need for those now, so we don't parse them.)
149156 int extendedBeginning = RoundUpToEven ( StringsTableOffset + _stringTableNumBytes ) ;
150- _extendedStrings = ParseExtendedStrings ( data , extendedBeginning ) ?? new Dictionary < string , string > ( ) ;
157+ _extendedStrings = ParseExtendedStrings ( data , extendedBeginning , _readAs32Bit ) ?? new Dictionary < string , string > ( ) ;
151158 }
152159
153160 /// <summary>The name of the associated terminfo, if any.</summary>
@@ -278,7 +285,7 @@ private static Database ReadDatabase(string term, string directoryPath)
278285 /// The offset into data where the string offsets section begins. We index into this section
279286 /// to find the location within the strings table where a string value exists.
280287 /// </summary>
281- private int StringOffsetsOffset { get { return NumbersOffset + ( _numberSectionNumShorts * 2 ) ; } }
288+ private int StringOffsetsOffset { get { return NumbersOffset + ( _numberSectionNumShorts * _sizeOfInt ) ; } }
282289
283290 /// <summary>The offset into data where the string table exists.</summary>
284291 private int StringsTableOffset { get { return StringOffsetsOffset + ( _stringSectionNumOffsets * 2 ) ; } }
@@ -346,9 +353,10 @@ public int GetNumber(WellKnownNumbers numberIndex)
346353 /// defined as the earlier portions, and may not even exist, the parsing is more lenient about
347354 /// errors, returning an empty collection rather than throwing.
348355 /// </returns>
349- private static Dictionary < string , string > ParseExtendedStrings ( byte [ ] data , int extendedBeginning )
356+ private static Dictionary < string , string > ParseExtendedStrings ( byte [ ] data , int extendedBeginning , bool readAs32Bit )
350357 {
351358 const int ExtendedHeaderSize = 10 ;
359+ int sizeOfIntValuesInBytes = ( readAs32Bit ) ? 4 : 2 ;
352360 if ( extendedBeginning + ExtendedHeaderSize >= data . Length )
353361 {
354362 // Exit out as there's no extended information.
@@ -357,10 +365,10 @@ private static Dictionary<string, string> ParseExtendedStrings(byte[] data, int
357365
358366 // Read in extended counts, and exit out if we got any incorrect info
359367 int extendedBoolCount = ReadInt16 ( data , extendedBeginning ) ;
360- int extendedNumberCount = ReadInt16 ( data , extendedBeginning + 2 ) ;
361- int extendedStringCount = ReadInt16 ( data , extendedBeginning + 4 ) ;
362- int extendedStringNumOffsets = ReadInt16 ( data , extendedBeginning + 6 ) ;
363- int extendedStringTableByteSize = ReadInt16 ( data , extendedBeginning + 8 ) ;
368+ int extendedNumberCount = ReadInt16 ( data , extendedBeginning + ( 2 * 1 ) ) ;
369+ int extendedStringCount = ReadInt16 ( data , extendedBeginning + ( 2 * 2 ) ) ;
370+ int extendedStringNumOffsets = ReadInt16 ( data , extendedBeginning + ( 2 * 3 ) ) ;
371+ int extendedStringTableByteSize = ReadInt16 ( data , extendedBeginning + ( 2 * 4 ) ) ;
364372 if ( extendedBoolCount < 0 ||
365373 extendedNumberCount < 0 ||
366374 extendedStringCount < 0 ||
@@ -380,7 +388,7 @@ private static Dictionary<string, string> ParseExtendedStrings(byte[] data, int
380388 extendedBeginning + // go past the normal data
381389 ExtendedHeaderSize + // and past the extended header
382390 RoundUpToEven ( extendedBoolCount ) + // and past all of the extended Booleans
383- ( extendedNumberCount * 2 ) ; // and past all of the extended numbers
391+ ( extendedNumberCount * sizeOfIntValuesInBytes ) ; // and past all of the extended numbers
384392
385393 // Get the location where the extended string table begins. This area contains
386394 // null-terminated strings.
@@ -447,6 +455,14 @@ private static Dictionary<string, string> ParseExtendedStrings(byte[] data, int
447455
448456 private static int RoundUpToEven ( int i ) { return i % 2 == 1 ? i + 1 : i ; }
449457
458+ /// <summary>Read a 16-bit or 32-bit value from the buffer starting at the specified position.</summary>
459+ /// <param name="buffer">The buffer from which to read.</param>
460+ /// <param name="pos">The position at which to read.</param>
461+ /// <param name="readAs32Bit">Whether or not to read value as 32-bit. Will read as 16-bit if set to false.</param>
462+ /// <returns>The value read.</returns>
463+ private static int ReadInt ( byte [ ] buffer , int pos , bool readAs32Bit ) =>
464+ readAs32Bit ? ReadInt32 ( buffer , pos ) : ReadInt16 ( buffer , pos ) ;
465+
450466 /// <summary>Read a 16-bit value from the buffer starting at the specified position.</summary>
451467 /// <param name="buffer">The buffer from which to read.</param>
452468 /// <param name="pos">The position at which to read.</param>
@@ -458,6 +474,18 @@ private static short ReadInt16(byte[] buffer, int pos)
458474 ( ( int ) buffer [ pos ] & 0xff ) ) ) ;
459475 }
460476
477+ /// <summary>Read a 32-bit value from the buffer starting at the specified position.</summary>
478+ /// <param name="buffer">The buffer from which to read.</param>
479+ /// <param name="pos">The position at which to read.</param>
480+ /// <returns>The 32-bit value read.</returns>
481+ private static int ReadInt32 ( byte [ ] buffer , int pos )
482+ {
483+ return ( int ) ( ( buffer [ pos ] & 0xff ) |
484+ buffer [ pos + 1 ] << 8 |
485+ buffer [ pos + 2 ] << 16 |
486+ buffer [ pos + 3 ] << 24 ) ;
487+ }
488+
461489 /// <summary>Reads a string from the buffer starting at the specified position.</summary>
462490 /// <param name="buffer">The buffer from which to read.</param>
463491 /// <param name="pos">The position at which to read.</param>
0 commit comments