Custom CSV "report" in SQL
May I suggest to use views?  Consider the following tables (and test data):

-- T1
create table ihead (
  id number primary key
, col_a varchar2(32)
, col_b varchar2(32)
);

-- T2
create table irow (
  headid number references ihead(id)
, col1 varchar2(32)
, col2 varchar2(32)
, irowid number primary key
);


In the second table (that you have called T2), there should the rows should be numbered somehow, otherwise it will be hard to get to invoice details into the correct order - as @Bill has hinted.

-- test data
begin
  insert into ihead values (1, 'AAA', 'BBB');
  insert into ihead values (2, 'CCC', 'DDD');
  insert into irow values (1, 'eee', 'fff', 1);
  insert into irow values (1, 'ggg', 'hhh', 2);
  insert into irow values (2, 'iii', 'jjj', 3);
  insert into irow values (2, 'kkk', 'lll', 4);  
end;


I'd create a join first, and store it as a VIEW, like so:

-- join, similar to the first select you have written

create or replace view alldetails
as
select
  H.id, H.col_a, H.col_b, R.col1, R.col2, R.irowid
from 
  ihead H join irow R on id = headid;


Check the output:

select * from alldetails;
-- output
ID COL_A  COL_B  COL1  COL2  IROWID
1  AAA    BBB    eee   fff   1
1  AAA    BBB    ggg   hhh   2
2  CCC    DDD    iii   jjj   3
2  CCC    DDD    kkk   lll   4


Second view: get all INVOICE_HEADS (first select), then INVOICE_ROWS (second select) 

create or replace view idetails (c1, c2, c3, c4, irow)
as
select 'INVOICE_HEAD', col_a, col_b, col1, col2 from alldetails
where irowid in (
  select min(irowid) from iheader group by id
)
union
select 'INVOICE_ROW', null, null, col1, col2 from alldetails
where irowid not in (
  select min(irowid) from iheader group by id
)


Now we can just:

select * from idetails order by irow
-- output
C1              C2      C3      C4      IROW
INVOICE_HEAD    AAA     BBB     eee     fff
INVOICE_ROW     -       -       ggg     hhh
INVOICE_HEAD    CCC     DDD     iii     jjj
INVOICE_ROW     -       -       kkk     lll


Get to the final output by executing:

select 
  c1 ||';'|| c2 ||';'|| c3 ||';'|| c4 ||';'|| irow
from idetails
order by irow


-- final output (some padding added manually,
-- but can be done with RPAD or LPAD)

INVOICE_HEAD ; AAA ; BBB ; eee ; fff
INVOICE_ROW  ;     ;     ; ggg ; hhh
INVOICE_HEAD ; CCC ; DDD ; iii ; jjj
INVOICE_ROW  ;     ;     ; kkk ; lll


UPDATE 2017-05-17 (requirements have changed)

-- leave the first view as it is,
-- change the second view to be:
create or replace view idetails (
  c1, c2, c3, id, c4, c5, irowid )
as
select distinct 
  'INVOICE_HEAD', col_a, col_b, headid, null, null, 0 
from alldetails
union
select 
  'INVOICE_ROW', null, null, headid, col1, col2, irowid 
from alldetails;


Then, select all the columns you need (notice: 2 columns in the ORDER BY clause):

select 
  c1 ||';'|| c2 ||';'|| c3 ||';'|| c4 ||';'|| c5
from idetails
order by id, irowid;


Output (padding added by hand, just for clarity):

INVOICE_HEAD;AAA;BBB;   ;
INVOICE_ROW ;   ;   ;eee;fff
INVOICE_ROW ;   ;   ;ggg;hhh
INVOICE_HEAD;CCC;DDD;   ;
INVOICE_ROW ;   ;   ;iii;jjj
INVOICE_ROW ;   ;   ;kkk;lll