IDENTIFICATION DIVISION.
       PROGRAM-ID. MP3ID3INFO.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT MP3-FILE ASSIGN TO DYNAMIC WS-FILENAME
               ORGANIZATION IS BINARY SEQUENTIAL.

       DATA DIVISION.
       FILE SECTION.
       FD MP3-FILE.
       01 FILE-RECORD           PIC X(1).

       WORKING-STORAGE SECTION.
       *> Debug flag to enable/disable debug prints
       01 WS-DEBUG-MODE      PIC 9 VALUE 1.

       01 WS-FILENAME        PIC X(255) VALUE "audio.mp3".
       01 WS-EOF-FLAG        PIC 9 VALUE 0.
       88 WS-EOF         VALUE 1.
       
       *> Add a stop flag for zero-length frames
       01 STOP-READING-FLAG  PIC 9 VALUE 0.
       88 STOP-READING       VALUE 1.

       *> ID3v2 Header Structure
       01 ID3-HEADER.
           05 ID3-TAG         PIC X(3).      *> Should be "ID3"
           05 ID3-VERSION     PIC X(2).      *> Version (ID3v2.X)
           05 ID3-FLAGS       PIC X(1).      *> Flags
           05 ID3-SIZE        PIC X(4).      *> Sync-safe size

       *> Frame Structure
       01 ID3-FRAME-HEADER.
           05 ID3-FRAME-ID    PIC X(4).      *> Frame identifier
           05 ID3-FRAME-SIZE  PIC X(4).      *> Sync-safe frame size
           05 ID3-FRAME-FLAGS PIC X(2).      *> Frame flags

       *> Working variables - Use simpler COMP-5 instead of COMP for better debugger support
       01 WS-TAG-SIZE        PIC 9(9) COMP-5.
       01 WS-FRAME-SIZE      PIC 9(9) COMP-5.
       01 WS-CURRENT-POS     PIC 9(9) COMP-5.
       01 WS-REMAINING-BYTES PIC S9(9) COMP-5.
       01 WS-FILE-POS        PIC 9(9) COMP-5 VALUE 1.
       01 WS-I               PIC 9(9) COMP-5.

       *> Buffer for frame data - Keep fixed size for easier debugging
       01 WS-FRAME-DATA-SIZE  PIC 9(5) COMP-5 VALUE 100000.
       01 WS-FRAME-DATA.
           05 WS-FRAME-CHAR   PIC X OCCURS 100000 TIMES.

       *> Variables for sync-safe integer conversion
       01 WS-BYTE            PIC X OCCURS 4.
       01 WS-BYTE-VAL        PIC 9(3) COMP-5 OCCURS 4.

       *> Variables for sync-safe integer conversion
       01 SYNC-SAFE-INT-IN.
           05 SYNC-SAFE-INT-1 PIC X(1).
           05 SYNC-SAFE-INT-2 PIC X(1).
           05 SYNC-SAFE-INT-3 PIC X(1).
           05 SYNC-SAFE-INT-4 PIC X(1).

       01 SYNC-SAFE-INT-OUT PIC 9(9) COMP-5.

       *> Variables for zero-based ORD function
       01 WS-TEMP-CHAR       PIC X(1).
       01 WS-ORD-RESULT      PIC 9(5) COMP-5.

       01 WS-BYTES-TO-READ   PIC 9(5) COMP-5.
       01 BYTES-BUFFER       PIC X(100000).
       01 WS-TEMP-BYTE       PIC X(1).

       01 WS-VAL                PIC 9(7).
       01 WS-NEW-VAL            PIC 9(7).

       LINKAGE SECTION.
       01 LS-CHAR            PIC X(1).
       01 LS-ORD-RESULT      PIC 9(5) COMP-5.

       PROCEDURE DIVISION.
       MAIN-PARA.
           DISPLAY "Starting MP3-ID3-INFO program".

           PERFORM OPEN-FILE.

           IF WS-EOF-FLAG = 0
               PERFORM READ-ID3-HEADER
               IF ID3-TAG = "ID3"
                   PERFORM PROCESS-ID3-TAG
               ELSE
                    DISPLAY "No ID3v2 tag found!"
               END-IF
           END-IF.

           PERFORM CLOSE-FILE.

           DISPLAY "Program execution complete".
           STOP RUN.

       OPEN-FILE.
           DISPLAY "Opening file: " WS-FILENAME.
           OPEN INPUT MP3-FILE.
           IF WS-EOF-FLAG = 1
               DISPLAY "Error opening file!"
           END-IF.

       CLOSE-FILE.
           DISPLAY "Closing file".
           CLOSE MP3-FILE.

       *> Read ID3 header
       READ-ID3-HEADER.
           *> Read ID3 header (10 bytes)
           MOVE 10 TO WS-BYTES-TO-READ
           PERFORM READ-BYTES
           MOVE BYTES-BUFFER(1:10) TO ID3-HEADER.

       PROCESS-ID3-TAG.
           *> Get the size which is 4-byte sync-safe integer   
           MOVE ID3-SIZE TO SYNC-SAFE-INT-IN
           PERFORM CONVERT-SYNC-SAFE-INT
           MOVE SYNC-SAFE-INT-OUT TO WS-TAG-SIZE

           DISPLAY "ID3v2 Version: "
               FUNCTION TRIM(FUNCTION HEX-OF(ID3-VERSION(1:1))) "."
               FUNCTION TRIM(FUNCTION HEX-OF(ID3-VERSION(2:1))).

           *> Debug display
           IF WS-DEBUG-MODE = 1
               DISPLAY "Tag Size: " WS-TAG-SIZE " bytes"
           END-IF

           MOVE 10 TO WS-FILE-POS.  *> 10 bytes read so far (header)
           MOVE 0 TO STOP-READING-FLAG.  *> Reset the stop reading flag

           *> Debug line with explicit break opportunity
           DISPLAY "Starting to read frames at position " WS-FILE-POS.

           PERFORM READ-FRAMES
               UNTIL (WS-FILE-POS >= WS-TAG-SIZE + 10) OR 
                     WS-EOF OR 
                     STOP-READING.

       READ-FRAMES.
           *> Reset values
           MOVE LOW-VALUES TO ID3-FRAME-HEADER.
           MOVE 0  TO WS-FRAME-SIZE.

           *> Read frame header (10 bytes)
           MOVE 10 TO WS-BYTES-TO-READ
           PERFORM READ-BYTES
           MOVE BYTES-BUFFER(1:10) TO ID3-FRAME-HEADER

           *> Check for all null bytes - this is definitely padding
           IF ID3-FRAME-ID = LOW-VALUES
               DISPLAY "****************************************"
               DISPLAY "Found padding (all nulls) - stopping frame reading"
               DISPLAY "****************************************"
               MOVE 1 TO STOP-READING-FLAG
               EXIT PARAGRAPH
           END-IF.

           *> Update file position
           ADD 10 TO WS-FILE-POS.
           DISPLAY "Current position: " WS-FILE-POS.

           *> Get Frame length
           MOVE ID3-FRAME-SIZE TO SYNC-SAFE-INT-IN
           PERFORM CONVERT-SYNC-SAFE-INT
           MOVE SYNC-SAFE-INT-OUT TO WS-FRAME-SIZE

           IF WS-DEBUG-MODE = 1
               DISPLAY "-------------------------------"
               DISPLAY "FRAME HEADER: ID="
                   ID3-FRAME-ID
                   ", SIZE=" WS-FRAME-SIZE
           END-IF

           *> Check for invalid Frame Length
           IF WS-FRAME-SIZE < 0
               DISPLAY "Invalid WS-FRAME-SIZE " WS-FRAME-SIZE
               EXIT PARAGRAPH
           END-IF.

           *> Check for zero Frame Length - set stop flag and exit
           IF WS-FRAME-SIZE = 0
               DISPLAY "****************************************"
               DISPLAY "Frame length zero - stopping frame reading"
               DISPLAY "****************************************"
               MOVE 1 TO STOP-READING-FLAG
               EXIT PARAGRAPH
           END-IF.

           *> Check for buffer overrun
           IF WS-FRAME-SIZE > 100000
               DISPLAY "Frame too large to process: " WS-FRAME-SIZE
               PERFORM SKIP-FRAME
           ELSE
               PERFORM READ-FRAME-DATA
           END-IF.

           DISPLAY "Current position: " WS-FILE-POS.

           *> Update file position
           ADD WS-FRAME-SIZE TO WS-FILE-POS.

           COMPUTE WS-REMAINING-BYTES = (WS-TAG-SIZE + 10) - WS-FILE-POS.
           DISPLAY "Next position: " WS-FILE-POS.
           DISPLAY "Remaining: " WS-REMAINING-BYTES.

       SKIP-FRAME.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > WS-FRAME-SIZE
           READ MP3-FILE
               AT END MOVE 1 TO WS-EOF-FLAG
                   EXIT PERFORM
           END-READ
           END-PERFORM.

       *> Read the Frame data
       *> We ignore pictures
       READ-FRAME-DATA.
           DISPLAY "Reading frame data: " WS-FRAME-SIZE " bytes".
           MOVE LOW-VALUES TO WS-FRAME-DATA.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > WS-FRAME-SIZE
               *> Add bounds check to prevent index errors
               IF WS-I >= 1 AND WS-I <= 100000
                   READ MP3-FILE INTO WS-TEMP-BYTE
                       AT END 
                           MOVE 1 TO WS-EOF-FLAG
                           EXIT PERFORM
                   END-READ
                   MOVE WS-TEMP-BYTE TO WS-FRAME-CHAR(WS-I)
               ELSE
                   DISPLAY "WARNING: Index " WS-I 
                       " out of bounds (1-100000)"
                   EXIT PERFORM
               END-IF
           END-PERFORM.

           *> Display appropriate message based on frame ID
           IF ID3-FRAME-ID = "APIC"
               DISPLAY "Frame: " ID3-FRAME-ID
                " - Data: [Picture]"
           ELSE
               DISPLAY "Frame: " ID3-FRAME-ID
                " - Data: " FUNCTION TRIM(WS-FRAME-DATA)
           END-IF.

       *> Convert sync-safe integer to actual size
       *> Implementation of syncSafeToInt function using zero-based ORD
       *> Input: SYNC-SAFE-INT-IN (4 bytes)
       *> Output: SYNC-SAFE-INT-OUT (integer value)
       CONVERT-SYNC-SAFE-INT.
           MOVE 0 TO WS-VAL.

           *> Extract the numeric value of each byte
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 4
               MOVE SYNC-SAFE-INT-IN(WS-I:1) TO WS-TEMP-CHAR
               MOVE 0 TO WS-ORD-RESULT
               CALL "ZERO-BASED-ORD" USING WS-TEMP-CHAR, WS-ORD-RESULT
               MOVE WS-ORD-RESULT TO WS-BYTE-VAL(WS-I)
           END-PERFORM

           *> Debug display of input bytes
           IF WS-DEBUG-MODE = 1
               DISPLAY "Byte 1: " WS-BYTE-VAL(1)
                   " (hex: " FUNCTION HEX-OF(SYNC-SAFE-INT-IN(1:1)) ")"
               DISPLAY "Byte 2: " WS-BYTE-VAL(2)
                   " (hex: " FUNCTION HEX-OF(SYNC-SAFE-INT-IN(2:1)) ")"
               DISPLAY "Byte 3: " WS-BYTE-VAL(3)
                   " (hex: " FUNCTION HEX-OF(SYNC-SAFE-INT-IN(3:1)) ")"
               DISPLAY "Byte 4: " WS-BYTE-VAL(4)
                   " (hex: " FUNCTION HEX-OF(SYNC-SAFE-INT-IN(4:1)) ")"
            END-IF
          
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 4
               MULTIPLY WS-VAL BY 256 GIVING WS-VAL    
               MOVE WS-BYTE-VAL(WS-I) TO WS-NEW-VAL
               ADD WS-NEW-VAL TO WS-VAL
           END-PERFORM

           MOVE WS-VAL TO SYNC-SAFE-INT-OUT

           DISPLAY "Converted value: " SYNC-SAFE-INT-OUT.

       *> Input: WS-BYTES-TO-READ = number of bytes to read
       *> Output: BYTES-BUFFER filled with data
       READ-BYTES SECTION.
           MOVE SPACES TO BYTES-BUFFER
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL 
               WS-I > WS-BYTES-TO-READ

               READ MP3-FILE INTO WS-TEMP-BYTE
                   AT END
                       MOVE 1 TO WS-EOF-FLAG
                       EXIT PERFORM
               END-READ
               MOVE WS-TEMP-BYTE TO BYTES-BUFFER(WS-I:1)
           END-PERFORM.
