1%% -*- mode: erlang; tab-width: 4; indent-tabs-mode: 1; st-rulers: [70] -*-
2%% vim: ts=4 sw=4 ft=erlang noet
3%%%-------------------------------------------------------------------
4%%% @author Andrew Bennett <andrew@pixid.com>
5%%% @copyright 2014-2015, Andrew Bennett
6%%% @doc
7%%%
8%%% @end
9%%% Created :  12 Aug 2015 by Andrew Bennett <andrew@pixid.com>
10%%%-------------------------------------------------------------------
11-module(fips_testvector).
12
13%% API
14-export([from_binary/1]).
15-export([from_file/1]).
16-export([to_binary/1]).
17-export([to_file/2]).
18
19%%====================================================================
20%% API functions
21%%====================================================================
22
23from_binary(Binary) ->
24	Lines = binary:split(Binary, [<< $\n >>, << $\r >>], [global, trim]),
25	parse_lines(Lines, []).
26
27from_file(File) ->
28	case file:read_file(File) of
29		{ok, Binary} ->
30			from_binary(Binary);
31		ReadError ->
32			ReadError
33	end.
34
35to_binary(Vectors) when is_list(Vectors) ->
36	<<
37		<<
38			(case Vector of
39				{flag, Flag} ->
40					<< $[, Flag/binary, $], $\n >>;
41				{option, {Key, Val}} ->
42					<< $[, Key/binary, $\s, $=, $\s, Val/binary, $], $\n >>;
43				{token, Token} ->
44					<< Token/binary, $\n >>;
45				{vector, {Key, Val}, hex} ->
46					<< Key/binary, $\s, $=, $\s, (hex:bin_to_hex(Val))/binary, $\n >>;
47				{vector, {Key, Val}, int} ->
48					<< Key/binary, $\s, $=, $\s, (integer_to_binary(Val))/binary, $\n >>;
49				{vector, {Key, Val}, raw} ->
50					<< Key/binary, $\s, $=, $\s, Val/binary, $\n >>
51			end)/binary
52		>>
53		|| Vector <- Vectors
54	>>.
55
56to_file(File, State={_, _, _}) ->
57	Binary = to_binary(State),
58	file:write_file(File, Binary).
59
60%%%-------------------------------------------------------------------
61%%% Internal functions
62%%%-------------------------------------------------------------------
63
64%% @private
65parse_lines([], Acc) ->
66	lists:reverse(Acc);
67parse_lines([Line | Lines], Acc) ->
68	case parse_line(Line) of
69		skip ->
70			parse_lines(Lines, Acc);
71		Term ->
72			parse_lines(Lines, [Term | Acc])
73	end.
74
75%% @private
76parse_line(<< $#, _/binary >>) ->
77	skip;
78parse_line(<< $\s, Rest/binary >>) ->
79	parse_line(Rest);
80parse_line(<< $\t, Rest/binary >>) ->
81	parse_line(Rest);
82parse_line(<< $[, Rest/binary >>) ->
83	parse_option(Rest);
84parse_line(<<>>) ->
85	skip;
86parse_line(Rest) ->
87	parse_vector(Rest).
88
89%% @private
90parse_option(Rest) ->
91	case binary:match(Rest, << $] >>) of
92		{OptionEndPos, 1} ->
93			case binary:match(Rest, << $= >>) of
94				{EqualPos, 1} when EqualPos < OptionEndPos ->
95					Key = parse_option_key(binary:part(Rest, 0, EqualPos), <<>>),
96					Val = parse_option_val(binary:part(Rest, EqualPos + 1, OptionEndPos - EqualPos - 1), <<>>),
97					{option, {Key, Val}};
98				_ ->
99					Flag = binary:part(Rest, 0, OptionEndPos),
100					{flag, Flag}
101			end;
102		_ ->
103			erlang:error({badarg, [Rest]})
104	end.
105
106%% @private
107parse_option_key(<< $\s, Rest/binary >>, Key) ->
108	parse_option_key(Rest, Key);
109parse_option_key(<< $\t, Rest/binary >>, Key) ->
110	parse_option_key(Rest, Key);
111parse_option_key(<< C, Rest/binary >>, Key) ->
112	parse_option_key(Rest, << Key/binary, C >>);
113parse_option_key(<<>>, Key) ->
114	Key.
115
116%% @private
117parse_option_val(<< $\s, Rest/binary >>, Val) ->
118	parse_option_val(Rest, Val);
119parse_option_val(<< $\t, Rest/binary >>, Val) ->
120	parse_option_val(Rest, Val);
121parse_option_val(<< C, Rest/binary >>, Val) ->
122	parse_option_val(Rest, << Val/binary, C >>);
123parse_option_val(<<>>, Val) ->
124	Val.
125
126%% @private
127parse_vector(<< C, Rest/binary >>)
128		when (C >= $A andalso C =< $Z)
129		orelse (C >= $a andalso C =< $z)
130		orelse (C >= $0 andalso C =< $9) ->
131	parse_vector_key(Rest, << C >>);
132parse_vector(Rest) ->
133	erlang:error({badarg, [Rest]}).
134
135%% @private
136parse_vector_key(<< $=, Rest/binary >>, Key) ->
137	parse_vector_val(Rest, Key, <<>>, true);
138parse_vector_key(<< $\s, Rest/binary >>, Key) ->
139	parse_vector_key(Rest, Key);
140parse_vector_key(<< $\t, Rest/binary >>, Key) ->
141	parse_vector_key(Rest, Key);
142parse_vector_key(<< C, Rest/binary >>, Key)
143		when (C >= $A andalso C =< $Z)
144		orelse (C >= $a andalso C =< $z)
145		orelse (C >= $0 andalso C =< $9) ->
146	parse_vector_key(Rest, << Key/binary, C >>);
147parse_vector_key(<<>>, Key) ->
148	{token, Key};
149parse_vector_key(Rest, Key) ->
150	erlang:error({badarg, [Rest, Key]}).
151
152%% @private
153parse_vector_val(<< $#, _/binary >>, Key = << C, O, U, N, T >>, Bin, true)
154		when (C =:= $C orelse C =:= $c)
155		andalso (O =:= $O orelse O =:= $o)
156		andalso (U =:= $U orelse U =:= $u)
157		andalso (N =:= $N orelse N =:= $n)
158		andalso (T =:= $T orelse T =:= $t) ->
159	Val = binary_to_integer(Bin),
160	{vector, {Key, Val}, int};
161parse_vector_val(<< $#, _/binary >>, Key, Hex, true) ->
162	Val = hex:hex_to_bin(Hex),
163	{vector, {Key, Val}, hex};
164parse_vector_val(<< $#, _/binary >>, Key, Val, false) ->
165	{vector, {Key, Val}, raw};
166parse_vector_val(<< $\s, Rest/binary >>, Key, Val, true) ->
167	parse_vector_val(Rest, Key, Val, true);
168parse_vector_val(<< $\t, Rest/binary >>, Key, Val, true) ->
169	parse_vector_val(Rest, Key, Val, true);
170parse_vector_val(<< C, Rest/binary >>, Key, Val, true)
171		when (C >= $A andalso C =< $F)
172		orelse (C >= $a andalso C =< $f)
173		orelse (C >= $0 andalso C =< $9) ->
174	parse_vector_val(Rest, Key, << Val/binary, C >>, true);
175parse_vector_val(<< C, Rest/binary >>, Key, Val, _Hex) ->
176	parse_vector_val(Rest, Key, << Val/binary, C >>, false);
177parse_vector_val(<<>>, Key = << C, O, U, N, T >>, Bin, true)
178		when (C =:= $C orelse C =:= $c)
179		andalso (O =:= $O orelse O =:= $o)
180		andalso (U =:= $U orelse U =:= $u)
181		andalso (N =:= $N orelse N =:= $n)
182		andalso (T =:= $T orelse T =:= $t) ->
183	Val = binary_to_integer(Bin),
184	{vector, {Key, Val}, int};
185parse_vector_val(<<>>, Key = << L, E, N >>, Bin, true)
186		when (L =:= $L orelse L =:= $l)
187		andalso (E =:= $E orelse E =:= $e)
188		andalso (N =:= $N orelse N =:= $n) ->
189	Val = binary_to_integer(Bin),
190	{vector, {Key, Val}, int};
191parse_vector_val(<<>>, Key, Hex, true) ->
192	Val = hex:hex_to_bin(Hex),
193	{vector, {Key, Val}, hex};
194parse_vector_val(<<>>, Key, Val, false) ->
195	{vector, {Key, Val}, raw};
196parse_vector_val(Rest, Key, Val, Hex) ->
197	erlang:error({badarg, [Rest, Key, Val, Hex]}).
198