Copied Chip Data XML from Hostboot project

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I0a230be8ba2840768e2097fd4e479c8feb8fc452
diff --git a/xml/lib/BitRange.pm b/xml/lib/BitRange.pm
new file mode 100644
index 0000000..e9bce35
--- /dev/null
+++ b/xml/lib/BitRange.pm
@@ -0,0 +1,114 @@
+package BitRange;
+
+use warnings;
+use strict;
+
+use Data::Dumper;
+
+#-------------------------------------------------------------------------------
+
+# Takes a string of integers separated by ',' (concat) and ':' (range). Will
+# return a sorted list of the expanded strings.
+sub expand($)
+{
+    my ( $str ) = @_;
+
+    my @list;
+    for my $e ( split(/,/, $str) )
+    {
+        if ( $e =~ /([0-9]+):([0-9]+)/ )
+        {
+            push @list, $_ foreach ( int($1)..int($2) );
+        }
+        else
+        {
+            push @list, int($e);
+        }
+    }
+
+    return @list;
+}
+
+#-------------------------------------------------------------------------------
+
+sub __combineConsecutiveRanges($$;$$); # because it is called recursively
+
+sub __combineConsecutiveRanges($$;$$)
+{
+    my ( $in, $out, $first, $last ) = @_;
+
+    # Check if there are any elements in the input list.
+    if ( 0 < scalar @{$in} )
+    {
+        # Check if we have found any previous range elements.
+        if ( defined $first )
+        {
+            if ( defined $last )
+            {
+                # We have at least two in a range. Check if the next one is in
+                # the consecutive range.
+                if ( $last + 1 == $in->[0] )
+                {
+                    $last = shift @{$in};
+                }
+                # This range is done. Add to the list and start the next range.
+                else
+                {
+                    push @{$out}, "$first:$last";
+                    $first = shift @{$in};
+                    $last = undef;
+                }
+            }
+            else
+            {
+                # Only the first element in the range so far. Check if the next
+                # one is in the consecutive range.
+                if ( $first + 1 == $in->[0] )
+                {
+                    $last = shift @{$in};
+                }
+                # This range is done. Add to the list and start the next range.
+                else
+                {
+                    push @{$out}, "$first";
+                    $first = shift @{$in};
+                    $last = undef;
+                }
+            }
+        }
+        # No previous range elements. Get the first one.
+        else
+        {
+            $first = shift @{$in};
+            $last  = undef; # Just in case.
+        }
+
+        # Iterate again.
+        __combineConsecutiveRanges($in, $out, $first, $last);
+    }
+    # Nothing else in the input list. Add any trailing range elements.
+    elsif ( defined $first )
+    {
+        push @{$out}, "$first" . ((defined $last) ? ":$last" : "");
+    }
+}
+
+# Takes a reference to a list of integers. Any set of consecutive integers will
+# be combined using the ':' character to represent a range
+# (i.e. 0,1,2,3 => 0:3). The remaining non-consecutive integers will be combined
+# with ',' character (i.e. 0,2,3,5 => 0,2:3,5).
+sub compress($)
+{
+    my ( $in ) = @_;
+
+    # Next, combine all of the consecutive ranges.
+    my $out = [];
+    __combineConsecutiveRanges( $in, $out );
+
+    # Now, combine the non-consecutive elements and return the string.
+    return join( ',', @{$out} );
+}
+
+#-------------------------------------------------------------------------------
+
+1;