Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/perl -w
0002 # SPDX-License-Identifier: GPL-2.0-or-later
0003 #
0004 # Build a static ASN.1 Object Identified (OID) registry
0005 #
0006 # Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
0007 # Written by David Howells (dhowells@redhat.com)
0008 #
0009 
0010 use strict;
0011 
0012 my @names = ();
0013 my @oids = ();
0014 
0015 if ($#ARGV != 1) {
0016     print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
0017     exit(2);
0018 }
0019 
0020 #
0021 # Open the file to read from
0022 #
0023 open IN_FILE, "<$ARGV[0]" || die;
0024 while (<IN_FILE>) {
0025     chomp;
0026     if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
0027     push @names, $1;
0028     push @oids, $2;
0029     }
0030 }
0031 close IN_FILE || die;
0032 
0033 #
0034 # Open the files to write into
0035 #
0036 open C_FILE, ">$ARGV[1]" or die;
0037 print C_FILE "/*\n";
0038 print C_FILE " * Automatically generated by ", $0, ".  Do not edit\n";
0039 print C_FILE " */\n";
0040 
0041 #
0042 # Split the data up into separate lists and also determine the lengths of the
0043 # encoded data arrays.
0044 #
0045 my @indices = ();
0046 my @lengths = ();
0047 my $total_length = 0;
0048 
0049 for (my $i = 0; $i <= $#names; $i++) {
0050     my $name = $names[$i];
0051     my $oid = $oids[$i];
0052 
0053     my @components = split(/[.]/, $oid);
0054 
0055     # Determine the encoded length of this OID
0056     my $size = $#components;
0057     for (my $loop = 2; $loop <= $#components; $loop++) {
0058     my $c = $components[$loop];
0059 
0060     # We will base128 encode the number
0061     my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
0062     $tmp = int($tmp / 7);
0063     $size += $tmp;
0064     }
0065     push @lengths, $size;
0066     push @indices, $total_length;
0067     $total_length += $size;
0068 }
0069 
0070 #
0071 # Emit the look-up-by-OID index table
0072 #
0073 print C_FILE "\n";
0074 if ($total_length <= 255) {
0075     print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
0076 } else {
0077     print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
0078 }
0079 for (my $i = 0; $i <= $#names; $i++) {
0080     print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
0081 }
0082 print C_FILE "\t[OID__NR] = ", $total_length, "\n";
0083 print C_FILE "};\n";
0084 
0085 #
0086 # Encode the OIDs
0087 #
0088 my @encoded_oids = ();
0089 
0090 for (my $i = 0; $i <= $#names; $i++) {
0091     my @octets = ();
0092 
0093     my @components = split(/[.]/, $oids[$i]);
0094 
0095     push @octets, $components[0] * 40 + $components[1];
0096 
0097     for (my $loop = 2; $loop <= $#components; $loop++) {
0098     my $c = $components[$loop];
0099 
0100     # Base128 encode the number
0101     my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
0102     $tmp = int($tmp / 7);
0103 
0104     for (; $tmp > 0; $tmp--) {
0105         push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
0106     }
0107     push @octets, $c & 0x7f;
0108     }
0109 
0110     push @encoded_oids, \@octets;
0111 }
0112 
0113 #
0114 # Create a hash value for each OID
0115 #
0116 my @hash_values = ();
0117 for (my $i = 0; $i <= $#names; $i++) {
0118     my @octets = @{$encoded_oids[$i]};
0119 
0120     my $hash = $#octets;
0121     foreach (@octets) {
0122     $hash += $_ * 33;
0123     }
0124 
0125     $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
0126 
0127     push @hash_values, $hash & 0xff;
0128 }
0129 
0130 #
0131 # Emit the OID data
0132 #
0133 print C_FILE "\n";
0134 print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
0135 for (my $i = 0; $i <= $#names; $i++) {
0136     my @octets = @{$encoded_oids[$i]};
0137     print C_FILE "\t";
0138     print C_FILE $_, ", " foreach (@octets);
0139     print C_FILE "\t// ", $names[$i];
0140     print C_FILE "\n";
0141 }
0142 print C_FILE "};\n";
0143 
0144 #
0145 # Build the search index table (ordered by length then hash then content)
0146 #
0147 my @index_table = ( 0 .. $#names );
0148 
0149 @index_table = sort {
0150     my @octets_a = @{$encoded_oids[$a]};
0151     my @octets_b = @{$encoded_oids[$b]};
0152 
0153     return $hash_values[$a] <=> $hash_values[$b]
0154     if ($hash_values[$a] != $hash_values[$b]);
0155     return $#octets_a <=> $#octets_b
0156     if ($#octets_a != $#octets_b);
0157     for (my $i = $#octets_a; $i >= 0; $i--) {
0158     return $octets_a[$i] <=> $octets_b[$i]
0159         if ($octets_a[$i] != $octets_b[$i]);
0160     }
0161     return 0;
0162 
0163 } @index_table;
0164 
0165 #
0166 # Emit the search index and hash value table
0167 #
0168 print C_FILE "\n";
0169 print C_FILE "static const struct {\n";
0170 print C_FILE "\tunsigned char hash;\n";
0171 if ($#names <= 255) {
0172     print C_FILE "\tenum OID oid : 8;\n";
0173 } else {
0174     print C_FILE "\tenum OID oid : 16;\n";
0175 }
0176 print C_FILE "} oid_search_table[OID__NR] = {\n";
0177 for (my $i = 0; $i <= $#names; $i++) {
0178     my @octets = @{$encoded_oids[$index_table[$i]]};
0179     printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
0180        $i,
0181        $hash_values[$index_table[$i]],
0182        $names[$index_table[$i]]);
0183     printf C_FILE "%02x", $_ foreach (@octets);
0184     print C_FILE "\n";
0185 }
0186 print C_FILE "};\n";
0187 
0188 #
0189 # Emit the OID debugging name table
0190 #
0191 #print C_FILE "\n";
0192 #print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
0193 #
0194 #for (my $i = 0; $i <= $#names; $i++) {
0195 #    print C_FILE "\t\"", $names[$i], "\",\n"
0196 #}
0197 #print C_FILE "\t\"Unknown-OID\"\n";
0198 #print C_FILE "};\n";
0199 
0200 #
0201 # Polish off
0202 #
0203 close C_FILE or die;