1
%%%-------------------------------------------------------------------
2
%%% File : tft_binary.erl
3
%%% Author : Hakan Mattsson <hakan@erix.ericsson.se>
6
%%% Created : 24 May 2004 by Hakan Mattsson <hakan@erix.ericsson.se>
7
%%%-------------------------------------------------------------------
11
%%%-------------------------------------------------------------------
13
%%%-------------------------------------------------------------------
17
-export([prepare/6, open/6, read/1, write/2, abort/3]).
18
-export([prepare/5, open/5]).
20
-record(read_state, {options, blksize, bin, is_network_ascii, count}).
21
-record(write_state, {options, blksize, list, is_network_ascii}).
23
%%-------------------------------------------------------------------
25
%%-------------------------------------------------------------------
27
prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) ->
28
%% Kept for backwards compatibility
29
prepare(Access, Filename, Mode, SuggestedOptions, Initial).
31
prepare(Access, Bin, Mode, SuggestedOptions, []) ->
33
case catch handle_options(Access, Bin, Mode, SuggestedOptions) of
34
{ok, IsNetworkAscii, AcceptedOptions} when Access =:= read, binary(Bin) ->
35
State = #read_state{options = AcceptedOptions,
36
blksize = lookup_blksize(AcceptedOptions),
38
is_network_ascii = IsNetworkAscii,
40
{ok, AcceptedOptions, State};
41
{ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Bin =:= binary ->
42
State = #write_state{options = AcceptedOptions,
43
blksize = lookup_blksize(AcceptedOptions),
45
is_network_ascii = IsNetworkAscii},
46
{ok, AcceptedOptions, State};
47
{error, {Code, Text}} ->
50
prepare(_Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
51
{error, {undef, "Illegal callback options."}}.
53
%%-------------------------------------------------------------------
55
%%-------------------------------------------------------------------
57
open(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) ->
58
%% Kept for backwards compatibility
59
open(Access, Filename, Mode, SuggestedOptions, Initial).
61
open(Access, Bin, Mode, SuggestedOptions, []) ->
63
case prepare(Access, Bin, Mode, SuggestedOptions, []) of
64
{ok, AcceptedOptions, State} ->
65
open(Access, Bin, Mode, AcceptedOptions, State);
66
{error, {Code, Text}} ->
69
open(Access, Bin, Mode, NegotiatedOptions, State) ->
73
is_record(State, write_state) -> State#write_state.is_network_ascii;
74
is_record(State, read_state) -> State#read_state.is_network_ascii
76
case catch handle_options(Access, Bin, Mode, NegotiatedOptions) of
77
{ok, IsNetworkAscii2, Options}
78
when Options =:= NegotiatedOptions,
79
IsNetworkAscii =:= IsNetworkAscii2 ->
80
{ok, NegotiatedOptions, State};
81
{error, {Code, Text}} ->
85
%%-------------------------------------------------------------------
87
%%-------------------------------------------------------------------
89
read(#read_state{bin = Bin} = State) when is_binary(Bin) ->
90
BlkSize = State#read_state.blksize,
92
size(Bin) >= BlkSize ->
93
<<Block:BlkSize/binary, Bin2/binary>> = Bin,
94
State2 = State#read_state{bin = Bin2},
95
{more, Block, State2};
96
size(Bin) < BlkSize ->
97
{last, Bin, State#read_state.count}
100
%%-------------------------------------------------------------------
102
%%-------------------------------------------------------------------
104
write(Bin, #write_state{list = List} = State) when is_binary(Bin), is_list(List) ->
106
BlkSize = State#write_state.blksize,
109
{more, State#write_state{list = [Bin | List]}};
111
Bin2 = list_to_binary(lists:reverse([Bin | List])),
115
%%-------------------------------------------------------------------
117
%%-------------------------------------------------------------------
119
abort(_Code, _Text, #read_state{bin = Bin} = State)
120
when record(State, read_state), binary(Bin) ->
122
abort(_Code, _Text, #write_state{list = List} = State)
123
when record(State, write_state), list(List) ->
126
%%-------------------------------------------------------------------
128
%%-------------------------------------------------------------------
130
handle_options(Access, Bin, Mode, Options) ->
131
IsNetworkAscii = handle_mode(Mode),
132
Options2 = do_handle_options(Access, Bin, Options),
133
{ok, IsNetworkAscii, Options2}.
137
%% "netascii" -> true;
139
_ -> throw({error, {badop, "Illegal mode " ++ Mode}})
142
do_handle_options(Access, Bin, [{Key, Val} | T]) ->
146
read when Val =:= "0", binary(Bin) ->
147
Tsize = integer_to_list(size(Bin)),
148
[{Key, Tsize} | do_handle_options(Access, Bin, T)];
150
handle_integer(Access, Bin, Key, Val, T, 0, infinity)
153
handle_integer(Access, Bin, Key, Val, T, 8, 65464);
155
handle_integer(Access, Bin, Key, Val, T, 1, 255);
157
do_handle_options(Access, Bin, T)
159
do_handle_options(_Access, _Bin, []) ->
163
handle_integer(Access, Bin, Key, Val, Options, Min, Max) ->
164
case catch list_to_integer(Val) of
166
do_handle_options(Access, Bin, Options);
167
Int when Int >= Min, Int =< Max ->
168
[{Key, Val} | do_handle_options(Access, Bin, Options)];
169
Int when Int >= Min, Max =:= infinity ->
170
[{Key, Val} | do_handle_options(Access, Bin, Options)];
172
throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
175
lookup_blksize(Options) ->
176
case lists:keysearch("blksize", 1, Options) of
178
list_to_integer(Val);