11#if HAS_SPAN
22using System . Buffers ;
33#endif
4+ using System ;
45using System . Diagnostics ;
56using System . Runtime . CompilerServices ;
7+ using System . Text ;
68
79namespace QRCoder ;
810
@@ -109,34 +111,70 @@ public static QRCodeData GenerateQrCode(PayloadGenerator.Payload payload, ECCLev
109111 public static QRCodeData GenerateQrCode ( string plainText , ECCLevel eccLevel , bool forceUtf8 = false , bool utf8BOM = false , EciMode eciMode = EciMode . Default , int requestedVersion = - 1 )
110112 {
111113 eccLevel = ValidateECCLevel ( eccLevel ) ;
114+ // Create data segment from plain text
115+ var segment = CreateDataSegment ( plainText , forceUtf8 , utf8BOM , eciMode ) ;
116+ // Determine the appropriate version based on segment bit length
117+ int version = DetermineVersion ( segment , eccLevel , requestedVersion ) ;
118+ // Build the complete bit array for the determined version
119+ var completeBitArray = BuildBitArrayFromSegment ( segment , version ) ;
120+ return GenerateQrCode ( completeBitArray , eccLevel , version ) ;
121+ }
122+
123+ /// <summary>
124+ /// Creates a data segment from plain text, encoding it appropriately.
125+ /// </summary>
126+ private static DataSegment CreateDataSegment ( string plainText , bool forceUtf8 , bool utf8BOM , EciMode eciMode )
127+ {
112128 var encoding = GetEncodingFromPlaintext ( plainText , forceUtf8 ) ;
113129 var codedText = PlainTextToBinary ( plainText , encoding , eciMode , utf8BOM , forceUtf8 ) ;
114130 var dataInputLength = GetDataLength ( encoding , plainText , codedText , forceUtf8 ) ;
115- int version = requestedVersion ;
116- int minVersion = CapacityTables . CalculateMinimumVersion ( dataInputLength + ( eciMode != EciMode . Default ? 2 : 0 ) , encoding , eccLevel ) ;
117- if ( version == - 1 )
131+ return new DataSegment ( encoding , dataInputLength , codedText , eciMode ) ;
132+ }
133+
134+ /// <summary>
135+ /// Determines the appropriate QR code version based on the data segment and error correction level.
136+ /// Validates that the data fits within the requested version, or finds the minimum version if not specified.
137+ /// </summary>
138+ private static int DetermineVersion ( DataSegment segment , ECCLevel eccLevel , int version )
139+ {
140+ if ( ! CapacityTables . TryCalculateMinimumVersion ( segment , eccLevel , out var minVersion ) )
118141 {
119- version = minVersion ;
142+ return Throw ( eccLevel , segment . EncodingMode , version == - 1 ? 40 : version ) ;
143+ }
144+ else if ( version == - 1 )
145+ {
146+ return minVersion ;
120147 }
121148 else
122149 {
123150 //Version was passed as fixed version via parameter. Thus let's check if chosen version is valid.
124151 if ( minVersion > version )
125152 {
126153 // Use a throw-helper to avoid allocating a closure
127- Throw ( eccLevel , encoding , version ) ;
128-
129- static void Throw ( ECCLevel eccLevel , EncodingMode encoding , int version )
130- {
131- var maxSizeByte = CapacityTables . GetVersionInfo ( version ) . Details . First ( x => x . ErrorCorrectionLevel == eccLevel ) . CapacityDict [ encoding ] ;
132- throw new Exceptions . DataTooLongException ( eccLevel . ToString ( ) , encoding . ToString ( ) , version , maxSizeByte ) ;
133- }
154+ return Throw ( eccLevel , segment . EncodingMode , version ) ;
134155 }
156+ return version ;
135157 }
136158
137- var modeIndicatorLength = eciMode != EciMode . Default ? 16 : 4 ;
138- var countIndicatorLength = GetCountIndicatorLength ( version , encoding ) ;
139- var completeBitArrayLength = modeIndicatorLength + countIndicatorLength + codedText . Length ;
159+ static int Throw ( ECCLevel eccLevel , EncodingMode encoding , int version )
160+ {
161+ var maxSizeByte = CapacityTables . GetVersionInfo ( version ) . Details . First ( x => x . ErrorCorrectionLevel == eccLevel ) . CapacityDict [ encoding ] ;
162+ throw new Exceptions . DataTooLongException ( eccLevel . ToString ( ) , encoding . ToString ( ) , version , maxSizeByte ) ;
163+ }
164+ }
165+
166+ /// <summary>
167+ /// Builds a complete BitArray from a data segment for a specific QR code version.
168+ /// </summary>
169+ private static BitArray BuildBitArrayFromSegment ( DataSegment segment , int version )
170+ {
171+ // todo in subsequent PR: eliminate these local variables and directly access the struct
172+ var eciMode = segment . EciMode ;
173+ var encoding = segment . EncodingMode ;
174+ int dataInputLength = segment . CharacterCount ;
175+ var codedText = segment . Data ;
176+ int completeBitArrayLength = segment . GetBitLength ( version ) ;
177+ int countIndicatorLength = GetCountIndicatorLength ( version , segment . EncodingMode ) ;
140178
141179 var completeBitArray = new BitArray ( completeBitArrayLength ) ;
142180
@@ -156,7 +194,7 @@ static void Throw(ECCLevel eccLevel, EncodingMode encoding, int version)
156194 completeBitArray [ completeBitArrayIndex ++ ] = codedText [ i ] ;
157195 }
158196
159- return GenerateQrCode ( completeBitArray , eccLevel , version ) ;
197+ return completeBitArray ;
160198 }
161199
162200 /// <summary>
@@ -366,6 +404,7 @@ List<CodewordBlock> CalculateECCBlocks()
366404
367405 void AddCodeWordBlocks ( int blockNum , int blocksInGroup , int codewordsInGroup , int offset2 , int count , Polynom generatorPolynom )
368406 {
407+ _ = blockNum ;
369408 var groupLength = codewordsInGroup * 8 ;
370409 groupLength = groupLength > count ? count : groupLength ;
371410 for ( var i = 0 ; i < blocksInGroup ; i ++ )
0 commit comments