299 lines
10 KiB
COBOL
299 lines
10 KiB
COBOL
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.
|
|
01 RecordLength PIC 9(5) COMP-5.
|
|
*> 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.
|
|
|
|
*> ID3v2 Header Structure - Use simpler types for debugging
|
|
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 - Explicitly define each element for debugger
|
|
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.
|
|
01 WS-SHIFT-RESULT PIC 9(9) COMP-5 OCCURS 4.
|
|
01 WS-X-RESULT PIC 9(9) COMP-5 OCCURS 4.
|
|
01 WS-Y-RESULT PIC 9(9).
|
|
|
|
01 WS-NUMBER PIC 9(5) VALUE 21154.
|
|
01 WS-DIVIDEND PIC 9(5).
|
|
|
|
01 WS-BYTE-FIELD.
|
|
05 WS-IW-BYTE-0 PIC X(1).
|
|
05 WS-IW-BYTE-1 PIC X(1).
|
|
05 WS-IW-BYTE-2 PIC X(1).
|
|
05 WS-IW-BYTE-3 PIC X(1).
|
|
|
|
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.
|
|
|
|
*> Debug display variables - explicit single items for easier debugging
|
|
01 DBG-FRAME-SIZE PIC 9(9) COMP-5.
|
|
01 DBG-ASCII-ID PIC X(4).
|
|
01 DBG-LOOP-COUNT PIC 9(5) COMP-5.
|
|
|
|
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-SHIFT-21 PIC 9(7) COMP-5 VALUE 2097152.
|
|
01 WS-SHIFT-14 PIC 9(7) COMP-5 VALUE 16384.
|
|
01 WS-SHIFT-7 PIC 9(7) COMP-5 VALUE 128.
|
|
01 WS-SHIFT-0 PIC 9(7) COMP-5 VALUE 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)
|
|
|
|
*> 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.
|
|
|
|
READ-FRAMES.
|
|
*> Debug counter for frame reading
|
|
ADD 1 TO DBG-LOOP-COUNT
|
|
|
|
*> 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
|
|
|
|
*> 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 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.
|