Format ElfObj64

include "../include/prog.h" "../include/prog.oh"

#multithread unsafe
datax identifiers#1
data exports=not_an_id
datax main_id#1
value reg#1
datax flag_shows#1
charx is_compress#1
charx is_file_write#1
#
datax id_sel#1
#valuexu call_struct#1;vdata c_main^struct_ids;vdata c_pool^struct_ids_actionpool
datax id_stack#1
charx call_struct_bool#1
#
vdata path_mem=NULL
#4-7 is 0
charx filelength_offseted#1
data file_out=fd_error
#
datax action_id#1

#win32 with _
importx "memcpy" memcpy
importx "free" free

const Z_OK=0
importx "compressBound" compressBound
importx "compress" compress

#this is throwless here
^import "struct_ids" struct_ids 2
import "struct_ids_free_all" struct_ids_free_all
import "struct_ids_actionpool_filter" struct_ids_actionpool_filter

function identifiers_set(sd value)
    set globals.identifiers value
endfunction

function swf_frames_reg()
#set reg for later
	sd block
	set block struct_ids((ids_get),globals.main_id)
	set globals.reg block_get_size(block)
	sub globals.reg (WORD)
end
#p
function swf_sprite_frames_pointer(sd spriteid)
	sd block
	if spriteid!=globals.main_id
		setcall block struct_ids((ids_get),spriteid)
		setcall block block_get_mem(block)
		add block (WORD)
	else
		set block struct_ids((ids_get),globals.main_id) #0
		set block block_get_mem(block)
		add block globals.reg
	end
	return block
end

function frames_as_shows(sd ?f)
	set globals.flag_shows f
	and globals.flag_shows (flag_framesAsShows)
end

function free_sprite_id_actions(sd id)
	call struct_ids_actionpool_filter((ids_free),id)
	callg struct_ids_actionpool((ids_free),id)
	callg struct_ids_action((ids_free),id) #without g is ok here
end

function swf_mem_change_back()
	set globals.id_sel globals.main_id
end
function swf_mem_change_pool(sd id)    #this can be stackable, at debug titles, at normal usage is back at the main id
	#is after action_code_values_init
	set globals.id_stack globals.id_sel
	set globals.id_sel id
	set globals.call_struct_bool (TRUE)
end
function swf_mem_change_back_pool()
	set globals.id_sel globals.id_stack
	set globals.call_struct_bool (FALSE)
end
function swf_mem_free()
	#0 freeing all ids(main(exports,root+sprites),acs,pools) #also new sprite on error and change here will free here
	call struct_ids_free_all()
	if globals.path_mem!=(NULL)
		#1
		call mem_free(#globals.path_mem)
		#2 exports
		set globals.exports (not_an_id)
		#3 set of values
		call action_code_values_free()
		#4
		call push()
		#file
		if globals.file_out!=(fd_error)
			call file_close(#globals.file_out)
		endif
	endif
end

function swf_actionblock_get()
	sv p_block
	setcall p_block struct_ids_action((ids_get_pointer),globals.action_id)
	return p_block#
endfunction
#size
function swf_actionblock_get_size()
	sd memblock;setcall memblock swf_actionblock_get()
	callret block_get_size(memblock)
end
#mem
function swf_actionblock_get_mem_size(sv pmem,sd psize)
	sd memblock;setcall memblock swf_actionblock_get()
	call block_get_mem_size(memblock,pmem,psize)
end
function swf_actionblock_change_back()
	sd poolid
	set globals.action_id globals.main_id
	#
	sd root_poolid
	setcall root_poolid actionpoolid_root()
	setcall poolid actionpoolid()
	set poolid# root_poolid#
end

import "mem_free" mem_free
import "action_code_values_free" action_code_values_free
import "file_close" file_close
^import "block_get_mem" block_get_mem 1 #full return
import "block_get_mem_size" block_get_mem_size
import "bits_packs" bits_packs
import "word_swap_arg" word_swap_arg
import "block_get_size" block_get_size
import "block_reset_size" block_reset_size
import "push" push

^import "actionpoolid" actionpoolid
^import "actionpoolid_root" actionpoolid_root
^import "actionpool_currentblock" actionpool_currentblock #full

import "action_size" action_size
import "stack_to_word_arg" stack_to_word_arg
^import "word_arg_to_stack" word_arg_to_stack 1 #full return
import "is_ainit" is_ainit

#aftercallimport ebool

import "dtitles_frame" dtitles_frame
import "dtitles_frame_one" dtitles_frame_one
^import "strlen_of" strlen_of 2

#id
function identifiers_get()
	if globals.identifiers=(maxuint16) #from swf specitifactions, example, id field for a DefineSprite
		call error("max uint16 at identifiers")
	end
	inc globals.identifiers
	return globals.identifiers
endfunction

import "debug_spritedone" debug_spritedone
function free_sprite_id(sd id,sd finalId_or_containerId) #containerId for buttons
	call free_sprite_id_actions(id)
	call struct_ids((ids_free),id)
	callg debug_spritedone(id,finalId_or_containerId)
endfunction

import "error" error
^import "struct_ids_actionpool" struct_ids_actionpool 2
^import "struct_ids_action" struct_ids_action 2 #full
import "struct_ids_action_set" struct_ids_action_set
import "mem_block_add" mem_block_add
import "def_mem" def_mem
import "debug_show" debug_show
^import "memalloc" memalloc 1

import "pool_savepath_init" pool_savepath_init
import "action_code_values_init" action_code_values_init
import "push_init" push_init
import "file_open" file_open
import "file_write" file_write
import "file_write_mem" file_write_mem
function swf_mem_init(ss path,sd len,sd ?flags)
	#arg is file
	#len is filelength offset
	#flags
	if globals.path_mem!=(NULL)
		call error("The previous swf was not ended.")
	endif
	#0
	svu path_size
	setcall path_size strlen_of(path,1)
	setcall globals.path_mem memalloc(path_size)
	call memcpy(globals.path_mem,path,path_size)
	call pool_savepath_init(globals.path_mem)
	#1
	setcall globals.main_id def_mem()
	set globals.id_sel globals.main_id
	call swf_actionblock_init()
	set globals.call_struct_bool (FALSE)
	#2
	call exports_init()
	#3
	call action_code_values_init()
	#4
	call push_init()
	#
	sd test=flagpre_write_no;and test flags
	if test=0
		set globals.filelength_offseted len
		set globals.is_file_write (TRUE)
		and flags (flag_compress)
		if flags!=0
			set globals.is_compress (TRUE)
		else
			set globals.is_compress (FALSE)
		end
	else
		set globals.is_file_write (FALSE)
	end
end
function swf_mem(sd ?proc,sd arg,sd ?len)
	if globals.path_mem=(NULL)
	#swf_(placeobject...)->mem_exp_add;swf_sprite_(placeobject...)->mem_exp_change;swf_done->mem_exp_done
		call error("there isn't a swf started")
	endif
	if proc=(mem_exp_add)
		#blockMain blockPool
		sv p_block
		if globals.call_struct_bool=(FALSE)
			setcall p_block struct_ids((ids_get_pointer),globals.id_sel)
		else
			setcall p_block struct_ids_actionpool((ids_get_pointer),globals.id_sel)
		end
		call mem_block_add(p_block,arg,len)
	elseif proc=(mem_exp_change)
		set globals.id_sel arg
	else
	#if proc==(mem_exp_done)
		if globals.is_file_write=(TRUE)
			call swf_tag_end()

			sd block
			setcall block struct_ids((ids_get),globals.main_id)
			ss mem;sd ?size
			!xor size size ##same .c problem and stack variables
			call block_get_mem_size(block,#mem,#size)

			sd pointer
			set pointer mem
			add pointer globals.filelength_offseted
			set pointer# size

			setcall globals.file_out file_open(globals.path_mem,(_open_write))

			if globals.is_compress=(TRUE)
				set mem# (C)
				add globals.filelength_offseted (DWORD)
				call file_write(globals.file_out,mem,globals.filelength_offseted)
				sub size globals.filelength_offseted
				ss dest
				sv destsize
				set destsize compressBound(size)
				set dest memalloc(destsize)
				add pointer (DWORD)
				sd er;set er compress(dest,#destsize,pointer,size)
				if er=(Z_OK)
					call file_write_mem(globals.file_out,dest,destsize) #will compress at least a RECT,ui16,ui16 + a tag(9) with the background colors
					ret
				end
				call free(dest)
				call error("compress error")
			else
				call file_write(globals.file_out,mem,size)
			end
		end
	endelse
endfunction
function swf_mem_add(ss dest,sd ?size) #this is here only to evade .c number of arguments error
    callg swf_mem((mem_exp_add),dest,size)
endfunction
function swf_tag_end()
    callg swf_tag_recordheader_entry((End),0)
endfunction
function swf_tag_recordheader_entry(sd ?tag,sd ?size)
    if size<(recordheader_long_mark)
        sd tag_plus_size
        callg swf_tag_recordheader(#tag_plus_size,tag,size)
    else
        callg swf_tag_recordheader_long_entry(tag,size)
    endelse
endfunction
function swf_tag_recordheader_long_entry(sd ?tag,sd ?size)
    sd tag_plus_size
    call swf_tag_recordheader(#tag_plus_size,tag,(recordheader_long_mark))
    callg swf_mem_add(#size,(DWORD))
endfunction
const short_header=2
function swf_tag_recordheader(ss dest,sd ?tag,sd ?size)
    call bits_packs(dest,2,tag,10,size,6)
    call word_swap_arg(dest)
    callg swf_mem_add(dest,(short_header))
endfunction
function swf_tag(ss dest,sd ?tag,sd ?size)
    call swf_tag_recordheader(dest,tag,size)
    add dest (short_header)
    callg swf_mem_add(dest,size)
endfunction

function swf_frames_inc(sd ?frames,sw pointer)
	if frames=(maxuint16)  #example, frame count at DefineSprite
		call error("max uint16 at frames")
	end
	inc frames      ##even if is not a ShowFrame in the swf, is action that resides in a frame, ffdec is saying same
	call stack_to_word_arg(frames,pointer)
end
import "write_action" write_action
#size
function done_action(sd ?id,sd ?frames)
	sv p_block
	setcall p_block struct_ids_action((ids_get_pointer),id)
	sd block
	set block p_block#
	sd ?size
	setcall size block_get_size(block)
	if size!=0  #here is an ending from show or done with size
		sd ?tagsz
		call dtitles_frame(frames)
		setcall tagsz action_size(id)
		call swf_tag_recordheader_entry((DoAction),tagsz)
		call write_action(id,frames)
		sd poolblock
		setcall poolblock actionpool_currentblock()
		call block_reset_size(poolblock)
		call block_reset_size(block)
	end
	return size
end
import "write_action_one" write_action_one
function done_action_one(sd id,sd finalid)
	sv p_block
	setcall p_block struct_ids_action((ids_get_pointer),id)
	sd block
	set block p_block#
	sd size
	setcall size block_get_size(block)
	if size!=0  #here is an ending from show or done with size
		sd tagsz
		call dtitles_frame_one(id,finalid)
		setcall tagsz action_size(id)
		add tagsz (WORD)
		call swf_tag_recordheader_entry((DoInitAction),tagsz)
		call swf_mem_add(#finalid,(WORD))
		callg write_action_one(id)
	end
end
import "pool_read" pool_read
function swf_actionblock_init()
	set globals.action_id globals.main_id
	sd p_poolid;setcall p_poolid actionpoolid();set p_poolid# globals.action_id
	sd p_poolrootid;setcall p_poolrootid actionpoolid_root();set p_poolrootid# globals.action_id

	call struct_ids_action_set(globals.action_id,(xlog_ainit_false)) #see at part_done call struct_ids_action_set(id,(TRUE))
	callg pool_read(globals.action_id,0)
end
function swf_actionblock_change(sd ?id)
	#must verify to be a valid user input id
	call struct_ids_actionpool((ids_get_pointer),id)
	sd poolid
	set globals.action_id id
	setcall poolid actionpoolid()
	set poolid# globals.action_id
end
function swf_actionblock_done(sd type)
	sd ?frames;sd pframes
	set pframes swf_sprite_frames_pointer(globals.action_id)
	set frames word_arg_to_stack(pframes)

	#call is_ainit((xlog_ainit_true)) this is not similiar with DoAction, has spriteid and only once per swf, and ffdec is forgetting the sprite id
	# and, at ruffle, can add in multiple frames, but are executed all at once before any frames, and "this" is level0 for all
	#then, this at done

	sd ?sz
	call is_ainit((xlog_ainit_false))
	set sz done_action(globals.action_id,frames)

	if type=(from_show) #example: two action() and one show here
		call debug_show(globals.action_id) #id is 0/spriteid, this is good at debugger to keep the count of frames
		set pframes swf_sprite_frames_pointer(globals.action_id) #mem was increased, pointer (maybe) was changed
		call swf_frames_inc(frames,pframes)
		if sz=0 # else is an ending from show with no size
			inc frames
			call pool_read(globals.action_id,frames)
		end
	elseif globals.flag_shows=0
		if sz!=0
			set pframes swf_sprite_frames_pointer(globals.action_id)
			call swf_frames_inc(frames,pframes)
		elseif frames=0 #here is an ending from done with no size and no previous show
			set pframes swf_sprite_frames_pointer(globals.action_id)
			call swf_frames_inc(frames,pframes) #a default frame, how was before at root, and at sprite is ok, at normal there is at least one tag inside
		end
	end
endfunction

function swf_actionblock_add(sd value,sd size)
	sv p_block
	setcall p_block struct_ids_action((ids_get_pointer),globals.action_id)
	callg mem_block_add(p_block,value,size)
endfunction
import "debug_phase_code_add_if" debug_phase_code_add_if
function actionrecordheader_core(sd ?tag,sd ?size)
	char ar#actionrecordheader_size;ss arh^ar
	set arh# tag
	ss psz=actionrecordheader_tag_size
	add psz arh
	call stack_to_word_arg(size,psz)
	call swf_actionblock_add(arh,(actionrecordheader_size))
	callg debug_phase_code_add_if((TRUE),psz)
end
import "actionpush" actionpush
function actionrecordheader(sd tag,sd size)
#push pool dummy_jump( },for(a;,continue ) store(mixt,enum) if(remForIns) write_jump(breakW,breakForIn) writeif_jump(_add(forin,ifwithnot),break) jump(else) goto definef
	call actionpush()
	call actionrecordheader_core(tag,size)
endfunction
function swf_actionrecordheader(sd tag,sd size)
    char t#1
    char length#2
    set t tag
    call stack_to_word_arg(size,#length)
    call swf_mem_add(#t,3)
endfunction

#preid
function new_sprite_id()
	sd id
	setcall id def_mem()
	call struct_ids_action_set(id,(xlog_ainit_true)) #at button and normal sprite
	return id
endfunction

#
function exports_init()
    sd id
    setcall id def_mem()
    set globals.exports id
endfunction
#id
function exportsId_get()
    if globals.exports=(not_an_id);call error("Do not call the exports at this moment.");endif
    return globals.exports
endfunction

function swf_showframe_base() #sd frames_pointer
#showframe tag
	call swf_actionblock_done((from_show)) #,frames_pointer
	call swf_tag_recordheader_entry((ShowFrame),0)
endfunction

entryraw globals()
