Initial check

This commit is contained in:
Iain (Bill) Wiseman 2025-05-05 14:40:06 +12:00
commit 788e96bf08
8 changed files with 538 additions and 0 deletions

31
.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
# Ignore build artifacts
*.o
*.so
*.exe
*.int
*.lst
*.idb
*.log
*.bak
*~
*.i
*.c
*.c.h
*.c.l.h
# Ignore compiled executables
id3cobol
zero-ord
# Ignore temporary files
.DS_Store
*.swp
*.tmp
*.temp
# Ignore system-specific files
*.core
# Ignore intermediate .i files
audio.mp3

17
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "COBOL debugger",
"type": "gdb",
"preLaunchTask": "Build All",
"request": "launch",
"cobcargs": ["-free", "-x", "-g","-debug", "-Wall", "-O0"] ,
"group": ["id3cobol.cbl"],
"env": {
"COB_LIBRARY_PATH": "${workspaceFolder}",
"COB_PRE_LOAD": "zero-ord",
}
}
]
}

62
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,62 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build zero-ord module",
"type": "shell",
"command": "cobc",
"args": [
"-free",
"-m",
"-g",
"-debug",
"-Wall",
"-O0",
"zero-ord.cbl"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Build id3cobol",
"type": "shell",
"command": "cobc",
"args": [
"-free",
"-x",
"-g",
"-debug",
"-Wall",
"-O0",
"id3cobol.cbl"
],
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Build All",
"dependsOrder": "sequence",
"dependsOn": [
"Build zero-ord module",
"Build id3cobol"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
}
]
}

57
Makefile Normal file
View File

@ -0,0 +1,57 @@
# Makefile for COBOL project cleanup and building
# Created on: May 4, 2025
# Compiler settings
COBC = cobc
COBFLAGS = -x -g -debug -Wall
COBFLAGS_DEBUG = -x -g -debug -Wall -O0
# Source files
SOURCES = hello.cob hello.cbl hello2.cbl
C_SOURCES = hello.c hello2.c
# Executables
EXECS = hello hello2
# Default target
all: $(EXECS)
# Build rules
hello: hello.cob
$(COBC) $(COBFLAGS) -o $@ $<
hello.cbl.exe: hello.cbl
$(COBC) $(COBFLAGS_DEBUG) -o $@ $<
hello2: hello2.cbl
$(COBC) $(COBFLAGS) -o $@ $<
# Clean up intermediate files and executables
clean:
rm -f *.o *.so *.exe *.int *.lst *.idb *.c *.h *.i *.c.h
rm -f id3cobol zero-ord
# Deep clean (includes all build artifacts)
distclean: clean
rm -f *.log *.bak *~
# Debug build with optimizations disabled
debug: COBFLAGS = $(COBFLAGS_DEBUG)
debug: all
# Help target
help:
@echo "Makefile targets:"
@echo " all - Build all executables (default)"
@echo " clean - Remove intermediate files (.i, .c, .c.h, etc.)"
@echo " distclean - Remove intermediate files and executables"
@echo " debug - Build with full debug options and no optimization"
@echo " hello - Build only hello executable"
@echo " hello2 - Build only hello2 executable"
@echo ""
@echo "Examples:"
@echo " make clean - Clean intermediate files"
@echo " make debug - Build with debugging enabled"
# Prevent conflicts with files named like our targets
.PHONY: all clean distclean debug help

61
README.md Normal file
View File

@ -0,0 +1,61 @@
# MP3 ID3 Tag Reader
![GnuCOBOL](https://img.shields.io/badge/GnuCOBOL-3.2.0%2B-blue)
![Fun COBOL Image](assets/images/cobol.png)
This project is a COBOL-based MP3 ID3 tag reader that parses and displays metadata from MP3 files. It uses GnuCOBOL for compilation and execution.
## Software Requirements
- **GnuCOBOL**: Version 3.2.0 or later
- Ensure GnuCOBOL is installed and accessible via the `cobc` command.
- **Operating System**: Linux (tested on May 5, 2025)
- **Make**: Version 4.3 or later (for building the project)
- **Git**: Version 2.30.0 or later (for version control)
## Project Structure
- `id3cobol.cbl`: Main COBOL program for reading and parsing MP3 ID3 tags.
- `zero-ord.cbl`: COBOL module for zero-based ordinal conversion.
- `Makefile`: Build automation file for compiling and cleaning the project.
- `.gitignore`: Specifies files and directories to be ignored by Git.
## Build Instructions
1. **Compile the `zero-ord` module**:
```bash
make zero-ord
```
2. **Compile the `id3cobol` program**:
```bash
make id3cobol
```
3. **Clean up build artifacts**:
```bash
make clean
```
4. **Perform a deep clean (removes all artifacts)**:
```bash
make distclean
```
## Usage
Run the compiled `id3cobol` program to parse the `audio.mp3` file:
```bash
./id3cobol
```
> **Note**: Ensure you have an `audio.mp3` file in the same directory as the program. This file is required for the program to function.
## Debugging
To enable debugging, ensure the `WS-DEBUG-MODE` variable in `id3cobol.cbl` is set to `1`. This will display additional debug information during execution.
## License
This project is licensed under the MIT License. See the LICENSE file for details.

BIN
assets/images/cobol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

298
id3cobol.cbl Normal file
View File

@ -0,0 +1,298 @@
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.

12
zero-ord.cbl Normal file
View File

@ -0,0 +1,12 @@
IDENTIFICATION DIVISION.
PROGRAM-ID. ZERO-BASED-ORD.
DATA DIVISION.
LINKAGE SECTION.
01 LS-CHAR PIC X(1).
01 LS-ORD-RESULT PIC 9(5) COMP-5.
PROCEDURE DIVISION USING LS-CHAR, LS-ORD-RESULT.
COMPUTE LS-ORD-RESULT = FUNCTION ORD(LS-CHAR) - 1.
EXIT PROGRAM.
END PROGRAM ZERO-BASED-ORD.