Back to home page

LXR

 
 

    


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