package t::lib::Boot;

use strict;
use Carp;
use vars qw(@ISA $VERSION);

$VERSION = 0.11;

# revised 2015-03-21
#
# Copyright © 2004-2020 by William B. Birkett
#
# reads an ICC profile's profile header and tag table

# create bootstrap profile object
# parameters: (path_to_profile)
# returns: (ref_to_profile_object)
sub new {

	# get object class
	my $class = shift();

	# create empty profile object
	my $self = [
		{},  # object header
		[],  # profile header
		[]   # tag table
	];

	# if one parameter, a file path
	if (@_ == 1 && ! ref($_[0]) && -f $_[0]) {
		
		# read data from ICC profile
		_readICCprofile($self, @_) || croak("couldn't read profile: $_[0]\n");
		
	}

	# bless object
	bless($self, $class);

	# return object reference
	return($self);

}

# get reference to profile header
# returns: (ref_to_profile_header_array)
sub profile_header {

	# get tag reference
	my $self = shift();

	# return reference to header
	return($self->[1]);

}

# get reference to profile tag table
# returns: (ref_to_profile_tag_table_array)
sub tag_table {

	# get tag reference
	my $self = shift();

	# return reference to header
	return($self->[2]);

}

# get file handle
# returns: (file_handle)
sub fh {

	# get tag reference
	my $self = shift();

	# return file handle
	return($self->[3]);

}

# read data from ICC profile
# parameters: (ref_to_object, path_to_profile)
# returns: (success_flag)
sub _readICCprofile {

	# get parameters
	my ($self, $path) = @_;

	# local variables
	my ($fh, $buf);

	# open the profile file
	open($fh, $path) || return(0);

	# set binary mode
	binmode($fh);

	# save file handle
	$self->[3] = $fh;

	# seek to profile file signature
	seek($fh, 36, 0);

	# read profile file signature
	read($fh, $buf, 4);

	# return if not an ICC profile
	($buf eq 'acsp') || return(0);

	# read the header
	_readICCheader($fh, $self->[1]) || return(0);

	# read the tag table
	_readICCtagtable($fh, $self->[2]) || return(0);

	# return
	return(1);

}

# read ICC header
# parameters: (file_handle, ref_to_header_array)
# returns: (success_flag)
sub _readICCheader {

	# get parameters
	my ($fh, $header) = @_;

	# local variables
	my ($buf, $check);

	# seek to start of header
	seek($fh, 0, 0);

	# read the header (128 bytes)
	(read($fh, $buf, 128) == 128) || return(0);

	# unpack the header
	@{$header} = unpack('N a4 H8 a4 a4 a4 n6 a4 a4 N a4 a4 N2 N N3 a4 H32 x28', $buf);

	# return success if profile file signature verified
	return($header->[12] eq 'acsp' ? 1 : 0);

}

# read ICC tag table
# parameters: (file_handle, ref_to_tag_table_array)
# returns: (success_flag)
sub _readICCtagtable {

	# get parameters
	my ($fh, $tagtab) = @_;

	# local variables
	my ($buf, $i, $n);

	# seek to start of tag table
	seek($fh, 128, 0);

	# read tag count (4 bytes)
	(read($fh, $buf, 4) == 4) || return(0);

	# unpack tag count
	$n = unpack('N', $buf);

	# read tag entries
	for $i (0 .. $n - 1) {
		
		# read tag entry (12 bytes)
		(read($fh, $buf, 12) == 12) || return(0) ;
		
		# unpack tag entry
		@{$tagtab->[$i]} = unpack('a4 N N', $buf);
		
	}

	# return
	return(1);

}

1;
