-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathJavaInfo
More file actions
162 lines (153 loc) · 4.33 KB
/
JavaInfo
File metadata and controls
162 lines (153 loc) · 4.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/perl
################################################################################
# JavaInfo - Java Class File Version Analyzer
#
# This utility extracts Java version information from compiled class files by
# reading their bytecode headers. It recursively processes files and directories
# to identify Java class files and report their compilation version.
#
# The script reads the first 8 bytes of each file, checks for the Java class
# file magic number (0xCAFEBABE), and extracts the major/minor version numbers
# which indicate the Java version used to compile the class.
#
# Usage: JavaInfo <file or directory> [<file or directory> ...]
#
# Examples:
# JavaInfo MyClass.class
# JavaInfo /path/to/project/bin
# JavaInfo target/classes lib/*.jar
#
# Author: Thomas
# License: See LICENSE file
################################################################################
use strict;
use warnings;
use File::Spec::Functions;
#
# Main entry point - processes all command-line arguments
#
# Parameters:
# @_ - List of file or directory paths to process
#
sub main {
foreach my $node (@_) {
process_node($node);
}
}
#
# Process a filesystem node (file or directory)
#
# Determines whether the given path is a file or directory and dispatches
# to the appropriate handler function.
#
# Parameters:
# $node - Path to the filesystem node to process
#
sub process_node {
my $node = shift();
if (-f $node) {
process_file($node);
} elsif (-d $node) {
process_dir($node);
}
}
#
# Recursively process all files in a directory
#
# Reads all entries in the directory (excluding . and ..) and recursively
# processes each one by calling process_node.
#
# Parameters:
# $dir - Path to the directory to process
#
# Dies on error:
# - If the directory cannot be opened
# - If the directory contents cannot be read
#
sub process_dir {
my $dir = shift();
if (opendir(my $DIR, $dir)) {
if (my @nodes = readdir(DIR)) {
foreach my $node (no_upwards(@nodes)) {
process_node(catfile($dir, $node));
}
} else {
die "$dir: could not read directory ($!)\n";
}
closedir(DIR);
} else {
die "$dir: could not open directory ($!)\n";
}
}
#
# Process a single file and extract Java version information
#
# Reads the first 8 bytes of a file to check if it's a valid Java class file
# (identified by the magic number 0xCAFEBABE) and extracts version information
# from the bytecode header.
#
# Java class file format (first 8 bytes):
# Bytes 0-3: Magic number (0xCAFEBABE)
# Bytes 4-5: Minor version
# Bytes 6-7: Major version
#
# Version mapping:
# Major 45 (minor <=3): Java 1.0.2
# Major 45 (minor >3): Java 1.1.8
# Major 46: Java 1.2.2
# Major 47: Java 1.3.1
# Major 48: Java 1.4.2
# Major 49+: Java (major - 44) [e.g., 52 = Java 8, 61 = Java 17]
#
# Parameters:
# $file - Path to the file to process
#
# Dies on error:
# - If the file cannot be opened
# - If the file cannot be read
# - If the file is not a valid Java class file
#
sub process_file {
my $file = shift();
if (open(my $FILE, '<', $file)) {
binmode($FILE);
my $buffer;
if (read(FILE, $buffer, 8)) {
# Unpack the first 8 bytes as two 32-bit unsigned integers (big-endian)
my @fields = unpack('NN', $buffer);
# Check for Java class file magic number (0xCAFEBABE)
if ($fields[0] == 0xCAFEBABE) {
# Extract minor and major version numbers from the second 32-bit value
my $minor = ($fields[1] & 0xFF00) >> 16; ## no critic [Use of bitwise operator]: indeed
my $major = $fields[1] & 0x00FF; ## no critic [Use of bitwise operator]: indeed
my $version = '';
# Map major/minor version to Java release version
if ($major == 45) {
if ($minor <= 3) {
$version = '1.0.2';
} else {
$version = '1.1.8';
}
} elsif ($major == 46) {
$version = '1.2.2';
} elsif ($major == 47) {
$version = '1.3.1';
} elsif ($major == 48) {
$version = '1.4.2';
} elsif ($major >= 49) {
# Java 5 and later: version = major - 44
$version = ($major - 44);
}
print "$file: Java " . $version . " [" . $minor . "/" . $major . "]\n";
} else {
die "$file: not a java class file\n";
}
} else {
die "$file: could not read file ($!)\n";
}
close($FILE);
} else {
die "$file: could not open file ($!)\n";
}
}
main(@ARGV);