| 1 | -module(binbird). |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | -define(FILE_BUFFER_SIZE, 1024). |
|---|
| 5 | %% The best Bin Buffer Size is 4096 |
|---|
| 6 | -define(BIN_BUFFER_SIZE, 4096). |
|---|
| 7 | |
|---|
| 8 | get_handle(FileName) -> |
|---|
| 9 | erlang:spawn_monitor(fun() -> start(FileName) end). |
|---|
| 10 | |
|---|
| 11 | get_lines({Pid, MRef}) -> |
|---|
| 12 | Pid ! {get_lines, MRef, self()}, |
|---|
| 13 | receive |
|---|
| 14 | {{Data, Prep}, MRef} -> |
|---|
| 15 | case travel_bin_eval(Data) of |
|---|
| 16 | [H|T] -> |
|---|
| 17 | [<<Prep/binary, H/binary>> | T]; |
|---|
| 18 | [] -> |
|---|
| 19 | [Prep] |
|---|
| 20 | end; |
|---|
| 21 | {eof, MRef} -> |
|---|
| 22 | eof; |
|---|
| 23 | {'DOWN', MRef, _Type, Pid, _Info} -> |
|---|
| 24 | erlang:fault(file_closed) |
|---|
| 25 | end. |
|---|
| 26 | |
|---|
| 27 | close({Pid, _}) -> |
|---|
| 28 | Pid ! stop. |
|---|
| 29 | |
|---|
| 30 | start(FileName) -> |
|---|
| 31 | {ok, F} = file:open(FileName, [raw, binary]), |
|---|
| 32 | serve_lines(F, <<>>). |
|---|
| 33 | |
|---|
| 34 | serve_lines(File,Rest) -> |
|---|
| 35 | {Data, Rest1} = get_more_data(File,Rest), |
|---|
| 36 | receive |
|---|
| 37 | {get_lines, Ref, Pid} -> |
|---|
| 38 | Pid ! {Data, Ref}, |
|---|
| 39 | serve_lines(File, Rest1); |
|---|
| 40 | stop -> |
|---|
| 41 | file:close(File) |
|---|
| 42 | end. |
|---|
| 43 | |
|---|
| 44 | get_more_data(File, Rest) -> |
|---|
| 45 | case file:read(File, ?FILE_BUFFER_SIZE) of |
|---|
| 46 | eof when size(Rest) =:= 0 -> |
|---|
| 47 | {eof, <<>>}; |
|---|
| 48 | eof -> |
|---|
| 49 | {{<<>>, Rest}, <<>>}; |
|---|
| 50 | {ok, Bin} -> |
|---|
| 51 | case get_last_line(Bin) of |
|---|
| 52 | {Lines, Rest1} -> |
|---|
| 53 | {{Lines, Rest}, Rest1}; |
|---|
| 54 | Rest1 -> |
|---|
| 55 | get_more_data(File, <<Rest/binary, Rest1/binary>>) |
|---|
| 56 | end |
|---|
| 57 | end. |
|---|
| 58 | |
|---|
| 59 | |
|---|
| 60 | %% @doc split Bin on character C |
|---|
| 61 | %% -spec(travel_bin_soft_hack/2::Bin::binary(), C:char() -> [binary]). |
|---|
| 62 | get_until(Bin, Str) -> |
|---|
| 63 | StrSize = length(Str), |
|---|
| 64 | get_until_1(Bin, Str, StrSize, 0, []). |
|---|
| 65 | |
|---|
| 66 | get_until_1(Bin, Str, StrSize, Offset, Acc) -> |
|---|
| 67 | %% Compiler will build a decision tree for following binary pattern matchs |
|---|
| 68 | %% and optimaze it, so, knows how many bits will be traveled and tested. |
|---|
| 69 | |
|---|
| 70 | case Bin of |
|---|
| 71 | <<_:Offset/binary,Str,_/binary>> -> |
|---|
| 72 | L = Offset, |
|---|
| 73 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 74 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 75 | <<_:Offset/binary,_,Str,_/binary>> -> |
|---|
| 76 | L = Offset + StrSize, |
|---|
| 77 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 78 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 79 | <<_:Offset/binary,_,_,Str,_/binary>> -> |
|---|
| 80 | L = Offset + 2 * StrSize, |
|---|
| 81 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 82 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 83 | <<_:Offset/binary,_,_,_,Str,_/binary>> -> |
|---|
| 84 | L = Offset + 3 * StrSize, |
|---|
| 85 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 86 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 87 | <<_:Offset/binary,_,_,_,_,Str,_/binary>> -> |
|---|
| 88 | L = Offset + 4 * StrSize, |
|---|
| 89 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 90 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 91 | <<_:Offset/binary,_,_,_,_,_,Str,_/binary>> -> |
|---|
| 92 | L = Offset + 5 * StrSize, |
|---|
| 93 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 94 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 95 | <<_:Offset/binary,_,_,_,_,_,_,Str,_/binary>> -> |
|---|
| 96 | L = Offset + 6 * StrSize, |
|---|
| 97 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 98 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 99 | <<_:Offset/binary,_,_,_,_,_,_,_,Str,_/binary>> -> |
|---|
| 100 | L = Offset + 7 * StrSize, |
|---|
| 101 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 102 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 103 | <<_:Offset/binary,_,_,_,_,_,_,_,_,Str,_/binary>> -> |
|---|
| 104 | L = Offset + 8 * StrSize, |
|---|
| 105 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 106 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 107 | <<_:Offset/binary,_,_,_,_,_,_,_,_,_,Str,_/binary>> -> |
|---|
| 108 | L = Offset + 9 * StrSize, |
|---|
| 109 | <<New:L/binary, _, Rest/binary>> = Bin, |
|---|
| 110 | split_bin_soft_hack(Rest, Str, 0, [New | Acc]); |
|---|
| 111 | <<_:Offset/binary,_:80,_/binary>> -> |
|---|
| 112 | split_bin_soft_hack(Bin, Str, Offset + 10 * StrSize, Acc); |
|---|
| 113 | <<_:Offset/binary,_,_/binary>> -> |
|---|
| 114 | split_bin_soft_hack(Bin, Str, Offset + 1 * StrSize, Acc); |
|---|
| 115 | _ -> |
|---|
| 116 | {Bin, lists:reverse(Acc)} |
|---|
| 117 | end. |
|---|