@@ -57,6 +57,10 @@ public static RuntimeScalar pack(RuntimeList args) {
5757 // Track if 'U' was used in normal mode (not byte mode)
5858 boolean hasUnicodeInNormalMode = false ;
5959
60+ // Stack to track byte order for nested groups
61+ java .util .Stack <Character > groupEndianStack = new java .util .Stack <>();
62+ groupEndianStack .push (' ' ); // Default: no specific endianness
63+
6064 for (int i = 0 ; i < template .length (); i ++) {
6165 char format = template .charAt (i );
6266
@@ -74,15 +78,37 @@ public static RuntimeScalar pack(RuntimeList args) {
7478 continue ;
7579 }
7680
77- // Skip spaces
78- if (Character .isWhitespace (format )) {
79- continue ;
80- }
81+ // Handle parentheses for grouping
82+ if (format == '(' ) {
83+ // Find matching closing parenthesis
84+ int closePos = findMatchingParen (template , i );
85+ if (closePos == -1 ) {
86+ throw new PerlCompilerException ("pack: unmatched parenthesis in template" );
87+ }
8188
82- // Skip comments
83- if (format == '#' ) {
84- // Skip to end of line or end of template
85- while (i + 1 < template .length () && template .charAt (i + 1 ) != '\n' ) {
89+ // Check for endianness modifier after the group
90+ char groupEndian = ' ' ; // default: inherit from parent
91+ if (closePos + 1 < template .length ()) {
92+ char nextChar = template .charAt (closePos + 1 );
93+ if (nextChar == '<' || nextChar == '>' ) {
94+ groupEndian = nextChar ;
95+ }
96+ }
97+
98+ // Extract group content
99+ String groupContent = template .substring (i + 1 , closePos );
100+
101+ // Check for conflicting endianness within the group
102+ if (groupEndian != ' ' && hasConflictingEndianness (groupContent , groupEndian )) {
103+ throw new PerlCompilerException ("Can't use both '<' and '>' in a group with different byte-order in pack" );
104+ }
105+
106+ // Process group (recursive pack)
107+ // For now, let's skip the actual processing and focus on the error detection
108+
109+ // Move past the group and any endianness modifier
110+ i = closePos ;
111+ if (closePos + 1 < template .length () && (template .charAt (closePos + 1 ) == '<' || template .charAt (closePos + 1 ) == '>' )) {
86112 i ++;
87113 }
88114 continue ;
@@ -563,4 +589,45 @@ private static boolean isNumericFormat(char format) {
563589 return false ;
564590 }
565591 }
592+
593+ private static int findMatchingParen (String template , int openPos ) {
594+ int depth = 1 ;
595+ for (int i = openPos + 1 ; i < template .length (); i ++) {
596+ if (template .charAt (i ) == '(' ) depth ++;
597+ else if (template .charAt (i ) == ')' ) {
598+ depth --;
599+ if (depth == 0 ) return i ;
600+ }
601+ }
602+ return -1 ;
603+ }
604+
605+ private static boolean hasConflictingEndianness (String groupContent , char groupEndian ) {
606+ // Check if the group content has endianness modifiers that conflict with the group's endianness
607+ for (int i = 0 ; i < groupContent .length (); i ++) {
608+ char c = groupContent .charAt (i );
609+ if ((c == '<' && groupEndian == '>' ) || (c == '>' && groupEndian == '<' )) {
610+ // Check if this is actually a modifier (follows a format that supports it)
611+ if (i > 0 ) {
612+ char prevChar = groupContent .charAt (i - 1 );
613+ if ("sSiIlLqQjJfFdDpP" .indexOf (prevChar ) >= 0 ) {
614+ return true ;
615+ }
616+ }
617+ }
618+ // Also check for nested groups with conflicting endianness
619+ if (c == '(' ) {
620+ int closePos = findMatchingParen (groupContent , i );
621+ if (closePos != -1 && closePos + 1 < groupContent .length ()) {
622+ char nestedEndian = groupContent .charAt (closePos + 1 );
623+ if ((nestedEndian == '<' && groupEndian == '>' ) ||
624+ (nestedEndian == '>' && groupEndian == '<' )) {
625+ return true ;
626+ }
627+ }
628+ i = closePos ; // Skip the nested group
629+ }
630+ }
631+ return false ;
632+ }
566633}
0 commit comments