diff --git a/.gitignore b/.gitignore index 4b777a3d16..b92c391471 100644 --- a/.gitignore +++ b/.gitignore @@ -15,15 +15,13 @@ /subprojects/libpng-*/ /subprojects/zlib-*/ /subprojects/packagecache -/subprojects/constgen/ /subprojects/SDATTool/ -/subprojects/knarc/ -/subprojects/narc/ /subprojects/metang/ /subprojects/rapidjson-*/ /subprojects/meson-*/ /subprojects/nitrorom/ /subprojects/metroskrew/ +/subprojects/.wraplock # Legacy mwrap compiler /tools/cw/mwrap diff --git a/asm/macros/btlanimcmd.inc b/asm/macros/btlanimcmd.inc index 8e56972d7e..23cba9ae62 100644 --- a/asm/macros/btlanimcmd.inc +++ b/asm/macros/btlanimcmd.inc @@ -1,10 +1,10 @@ #include "generated/sdat.h" #include "constants/battle/battle_anim.h" -#include "res/battle/particles/battle_particles.naix.h" -#include "res/graphics/battle/moves/anim_ncer.naix.h" -#include "res/graphics/battle/moves/anim_nanr.naix.h" -#include "res/graphics/battle/moves/anim_ncgr.naix.h" -#include "res/graphics/battle/moves/anim_nclr.naix.h" +#include "res/battle/particles/battle_particles.naix" +#include "res/graphics/battle/moves/anim_ncer.naix" +#include "res/graphics/battle/moves/anim_nanr.naix" +#include "res/graphics/battle/moves/anim_ncgr.naix" +#include "res/graphics/battle/moves/anim_nclr.naix" #include "macros/btlanimfunc.inc" @@ -415,7 +415,7 @@ // Loads a particle system from battle_particles.narc // particleSystem: The particle system to load. (0-15) - // narcMemberID: The member ID in battle_particles.narc to load (See battle_particles.naix.h) + // narcMemberID: The member ID in battle_particles.narc to load (See battle_particles.naix) // Note: Advanced use only, use LoadParticleResource instead. .macro LoadParticleSystem particleSystem:req, narcMemberID:req .long 51 @@ -610,7 +610,7 @@ // Loads a character resource into a sprite manager // managerID: ID of the sprite manager to load into (0-3) - // narcMemberIndex: Index of the character resource (See wechar.naix.h) + // narcMemberIndex: Index of the character resource (See wechar.naix) .macro LoadCharResObj managerID:req, narcMemberIndex:req .long 74 .long \managerID @@ -619,7 +619,7 @@ // Loads a palette resource into a sprite manager // managerID: ID of the sprite manager to load into (0-3) - // narcMemberIndex: Index of the palette resource (See wepltt.naix.h) + // narcMemberIndex: Index of the palette resource (See wepltt.naix) // paletteIndex: Index of the palette within the resource to load (0-15) .macro LoadPlttRes managerID:req, narcMemberIndex:req, paletteIndex:req .long 75 @@ -630,7 +630,7 @@ // Loads a cell resource into a sprite manager // managerID: ID of the sprite manager to load into (0-3) - // narcMemberIndex: Index of the cell resource (See wecell.naix.h) + // narcMemberIndex: Index of the cell resource (See wecell.naix) .macro LoadCellResObj managerID:req, narcMemberIndex:req .long 76 .long \managerID @@ -639,7 +639,7 @@ // Loads an animation resource into a sprite manager // managerID: ID of the sprite manager to load into (0-3) - // narcMemberIndex: Index of the animation resource (See wecellanm.naix.h) + // narcMemberIndex: Index of the animation resource (See wecellanm.naix) .macro LoadAnimResObj managerID:req, narcMemberIndex:req .long 77 .long \managerID @@ -730,7 +730,7 @@ // Loads a particle system from battle_particles.narc // particleSystem: The particle system to load. (0-15) - // narcMemberID: The member ID in battle_particles.narc to load (See battle_particles.naix.h) + // narcMemberID: The member ID in battle_particles.narc to load (See battle_particles.naix) .macro LoadParticleResource particleSystem:req, narcMemberID:req InitPokemonSpriteManager LoadPokemonSpriteDummyResources 0 diff --git a/include/data/map_headers.h b/include/data/map_headers.h index 41dce3cb84..84fcaeb477 100644 --- a/include/data/map_headers.h +++ b/include/data/map_headers.h @@ -7,11 +7,11 @@ #include "map_header.h" -#include "res/field/area_data/area_data.naix.h" -#include "res/field/encounters/pl_enc_data.naix.h" -#include "res/field/events/zone_event.naix.h" -#include "res/field/matrices/map_matrix.naix.h" -#include "res/field/scripts/scr_seq.naix.h" +#include "res/field/area_data/area_data.naix" +#include "res/field/encounters/pl_enc_data.naix" +#include "res/field/events/zone_event.naix" +#include "res/field/matrices/map_matrix.naix" +#include "res/field/scripts/scr_seq.naix" #include "res/text/bank/location_names.h" static const MapHeader sMapHeaders[] = { diff --git a/include/data/move_side_effect_subscripts.h b/include/data/move_side_effect_subscripts.h index 8477d716f2..b54cd013db 100644 --- a/include/data/move_side_effect_subscripts.h +++ b/include/data/move_side_effect_subscripts.h @@ -1,6 +1,6 @@ #include "constants/battle.h" -#include "res/battle/scripts/sub_seq.naix.h" +#include "res/battle/scripts/sub_seq.naix" // clang-format off static const int sSideEffectSubscripts[] = { diff --git a/include/narc_frontier_bg.h b/include/narc_frontier_bg.h index 94d9a164fd..c53c57821e 100644 --- a/include/narc_frontier_bg.h +++ b/include/narc_frontier_bg.h @@ -2,7 +2,7 @@ #define POKEPLATINUM_NARC_FRONTIER_BG_H // TODO This is a temporary header file for recording NARC indexes of // frontier_bg.narc. This file should eventually be deleted and the constants -// replaced with those from a naix.h file once the NARC is unpacked. +// replaced with those from a naix file once the NARC is unpacked. #define BATTLE_FACTORY_TILES 0 #define BATTLE_FACTORY_BATTLE_ROOM_TILEMAP 1 diff --git a/include/narc_frontier_obj.h b/include/narc_frontier_obj.h index 9d0b176a6a..1e6e3ad25c 100644 --- a/include/narc_frontier_obj.h +++ b/include/narc_frontier_obj.h @@ -2,7 +2,7 @@ #define POKEPLATINUM_NARC_FRONTIER_OBJ_H // TODO This is a temporary header file for recording NARC indexes of // frontier_obj.narc. This file should eventually be deleted and the constants -// replaced with those from a naix.h file once the NARC is unpacked. +// replaced with those from a naix file once the NARC is unpacked. #define BATTLE_HALL_APP_CURSOR_BOX_NCGR 12 #define BATTLE_HALL_APP_CURSOR_BOX_NANR 13 diff --git a/res/battle/moves/meson.build b/res/battle/moves/meson.build index 3cf254bb1b..0c9dbf48da 100644 --- a/res/battle/moves/meson.build +++ b/res/battle/moves/meson.build @@ -65,7 +65,7 @@ pl_waza_tbl_narc = custom_target('pl_waza_tbl.narc', depends: [ py_consts_generators ], command: [ movedata_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -131,11 +131,13 @@ anim_scripts_narc = custom_target(anim_scripts_narc_name, preserve_path_from: anim_scripts_root, ), command: [ - narc_exe, 'create', - '--order', anim_scripts_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--files-from', anim_scripts_order, + '--exclude', '*.d', + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += pl_waza_tbl_narc diff --git a/res/battle/particles/meson.build b/res/battle/particles/meson.build index 6ec300ad86..b959d99f11 100644 --- a/res/battle/particles/meson.build +++ b/res/battle/particles/meson.build @@ -488,26 +488,20 @@ battle_particle_files = files( 'shadow_force.spa', ) -battle_particles_basename = 'battle_particles' -battle_particles_narc_name = battle_particles_basename + '.narc' -battle_particles_naix_name = battle_particles_basename + '.naix.h' -battle_particles_order = files('battle_particles.order') - -battle_particles_narc = custom_target(battle_particles_narc_name, +battle_particles_narc = custom_target('battle_particles.narc', output: [ - battle_particles_narc_name, - battle_particles_naix_name + 'battle_particles.narc', + 'battle_particles.naix', ], - input: copy_gen.process( - battle_particle_files, - ), + input: copy_gen.process(battle_particle_files), command: [ - narc_exe, 'create', - '--naix', - '--order', battle_particles_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('battle_particles.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += battle_particles_narc diff --git a/res/battle/particles/pokeballs/meson.build b/res/battle/particles/pokeballs/meson.build index ea49b2d6bf..12e858c021 100644 --- a/res/battle/particles/pokeballs/meson.build +++ b/res/battle/particles/pokeballs/meson.build @@ -122,18 +122,19 @@ ball_particle_files = files( ball_particles_narc = custom_target('ball_particles.narc', output: [ 'ball_particles.narc', - 'ball_particles.naix.h', + 'ball_particles.naix', ], input: copy_gen.process( ball_particle_files, ), command: [ - narc_exe, 'create', - '--naix', - '--order', files('ball_particles.order'), - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('ball_particles.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += ball_particles_narc diff --git a/res/battle/scripts/common_anims/meson.build b/res/battle/scripts/common_anims/meson.build index 341a4875f2..2aaa273842 100644 --- a/res/battle/scripts/common_anims/meson.build +++ b/res/battle/scripts/common_anims/meson.build @@ -56,8 +56,7 @@ relative_build_dir = fs.relative_to(meson.current_build_dir(), meson.project_bui anim_subscripts_basename = 'anim_subscripts' anim_subscripts_narc_name = anim_subscripts_basename + '.narc' -anim_subscripts_naix_name = anim_subscripts_basename + '.naix.h' -anim_subscripts_order = files('anim_subscripts.order') +anim_subscripts_naix_name = anim_subscripts_basename + '.naix' anim_subscripts_private_dir = relative_build_dir / anim_subscripts_narc_name + '.p' @@ -71,12 +70,13 @@ anim_subscripts_narc = custom_target(anim_subscripts_narc_name, extra_args: [ '--out-dir', anim_subscripts_private_dir, ] ), command: [ - narc_exe, 'create', - '--naix', - '--order', anim_subscripts_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('anim_subscripts.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += anim_subscripts_narc diff --git a/res/battle/scripts/meson.build b/res/battle/scripts/meson.build index 36de684766..d1b12a33b0 100644 --- a/res/battle/scripts/meson.build +++ b/res/battle/scripts/meson.build @@ -10,7 +10,7 @@ waza_seq_target_name = 'waza_seq.narc' sub_seq_basename = 'sub_seq' sub_seq_narc_name = sub_seq_basename + '.narc' -sub_seq_naix_name = sub_seq_basename + '.naix.h' +sub_seq_naix_name = sub_seq_basename + '.naix' be_seq_private_dir = relative_build_dir / be_seq_target_name + '.p' sub_seq_private_dir = relative_build_dir / sub_seq_narc_name + '.p' @@ -23,10 +23,11 @@ be_seq_narc = custom_target(be_seq_target_name, extra_args: ['--out-dir', be_seq_private_dir] ), command: [ - narc_exe, 'create', - '--output', '@OUTPUT@', + nitroarc_exe, + '--create', + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) sub_seq_narc = custom_target(sub_seq_narc_name, @@ -39,12 +40,13 @@ sub_seq_narc = custom_target(sub_seq_narc_name, extra_args: ['--out-dir', sub_seq_private_dir] ), command: [ - narc_exe, 'create', - '--naix', - '--order', sub_seq_narc_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', sub_seq_narc_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) waza_seq_narc = custom_target(waza_seq_target_name, @@ -54,10 +56,11 @@ waza_seq_narc = custom_target(waza_seq_target_name, extra_args: ['--out-dir', waza_seq_private_dir] ), command: [ - narc_exe, 'create', - '--output', '@OUTPUT@', + nitroarc_exe, + '--create', + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += be_seq_narc diff --git a/res/field/area_data/meson.build b/res/field/area_data/meson.build index 8f1f90504e..9bc2c57010 100644 --- a/res/field/area_data/meson.build +++ b/res/field/area_data/meson.build @@ -1,14 +1,13 @@ -area_data_deps = [ - prop_model_set_narc[0], - map_texture_set_narc[0], - lighting_narc[0], -] - area_data_bin_gen = generator( area_data_py, arguments: [ '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', ], output: '@BASENAME@', - depends: [ py_consts_generators, area_data_deps ], + depends: [ + py_consts_generators, + prop_model_set_narc[1], + map_texture_set_narc[1], + lighting_narc[1], + ], ) area_data_srcs = files( @@ -89,32 +88,28 @@ area_data_srcs = files( 'area_data_074.json', ) -area_data_order = files('area_data.order') - area_data_narc = custom_target('area_data.narc', output: [ 'area_data.narc', 'area_data.naix', ], - input: [ - area_data_bin_gen.process(area_data_srcs, - env: jsoncnv_env, - extra_args: [ - '--map-prop-set-naix', prop_model_set_narc[1].full_path() + '.h', - '--map-texture-set-naix', map_texture_set_narc[1].full_path() + '.h', - '--lighting-set-naix', lighting_narc[1].full_path() + '.h', - ], - ), - area_data_order, - ], + input: area_data_bin_gen.process(area_data_srcs, + env: jsoncnv_env, + extra_args: [ + '--map-prop-set-naix', prop_model_set_narc[1].full_path(), + '--map-texture-set-naix', map_texture_set_narc[1].full_path(), + '--lighting-set-naix', lighting_narc[1].full_path(), + ], + ), depends: py_consts_generators, command: [ - narc_exe, 'create', - '--naix', - '--order', area_data_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('area_data.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += area_data_narc diff --git a/res/field/encounters/meson.build b/res/field/encounters/meson.build index 634bd3badc..b89f936b26 100644 --- a/res/field/encounters/meson.build +++ b/res/field/encounters/meson.build @@ -191,25 +191,21 @@ pl_enc_data_srcs = files( 'encounters_route_230.json', ) -pl_enc_data_order = files('encounters.order') - pl_enc_tbl_narc = custom_target('pl_enc_data.narc', output: [ 'pl_enc_data.narc', - 'pl_enc_data.naix.h', - ], - input: [ - enc_bin_gen.process(pl_enc_data_srcs, env: jsoncnv_env), - pl_enc_data_order + 'pl_enc_data.naix', ], + input: enc_bin_gen.process(pl_enc_data_srcs, env: jsoncnv_env), depends: [ py_consts_generators ], command: [ - narc_exe, 'create', - '--naix', - '--order', pl_enc_data_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('encounters.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) enc_ex_er_bin_gen = generator( @@ -255,8 +251,6 @@ encdata_ex_honey_trees_src = files('encounters_honey_tree.json') encdata_ex_trophy_garden_src = files('encounters_trophy_garden.json') encdata_ex_great_marsh_src = files('encounters_great_marsh_lookout.json') -encdata_ex_order = files('encdata_ex.order') - encdata_ex_narc = custom_target('encdata_ex.narc', output: 'encdata_ex.narc', input: [ @@ -264,16 +258,16 @@ encdata_ex_narc = custom_target('encdata_ex.narc', enc_ex_ht_bin_gen.process(encdata_ex_honey_trees_src, env: jsoncnv_env), enc_ex_tg_bin_gen.process(encdata_ex_trophy_garden_src, env: jsoncnv_env), enc_ex_gm_bin_gen.process(encdata_ex_great_marsh_src, env: jsoncnv_env), - encdata_ex_order ], env: jsoncnv_env, depends: [ py_consts_generators ], command: [ - narc_exe, 'create', - '--order', encdata_ex_order, - '--output', '@OUTPUT@', + nitroarc_exe, + '--create', + '--files-from', files('encdata_ex.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) zukan_enc_platinum_srcs = encdata_ex_elusive_rod_src @@ -289,7 +283,7 @@ pokedex_enc_platinum_narc = custom_target('zukan_enc_platinum.narc', depends: [ py_consts_generators ], command: [ make_pokedex_enc_platinum_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', diff --git a/res/field/events/meson.build b/res/field/events/meson.build index b7bbb17471..57ad5d28f9 100644 --- a/res/field/events/meson.build +++ b/res/field/events/meson.build @@ -561,17 +561,18 @@ events_order = files('zone_event.order') events_narc = custom_target('zone_event.narc', output: [ 'zone_event.narc', - 'zone_event.naix.h', + 'zone_event.naix', ], input: event_bin_gen.process(events_files, env: jsoncnv_env), depends: [ py_consts_generators, events_headers ], command: [ - narc_exe, 'create', - '--naix', - '--order', events_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('zone_event.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += events_narc diff --git a/res/field/frontier_scripts/meson.build b/res/field/frontier_scripts/meson.build index e15fee9ad5..198bed28d8 100644 --- a/res/field/frontier_scripts/meson.build +++ b/res/field/frontier_scripts/meson.build @@ -1,4 +1,3 @@ -relative_source_root = fs.relative_to(meson.project_source_root(), meson.project_build_root()) relative_build_dir = fs.relative_to(meson.current_build_dir(), meson.project_build_root()) fr_script_target_name = 'fr_script.narc' @@ -7,7 +6,7 @@ fr_script_private_dir = relative_build_dir / fr_script_target_name + '.p' fr_script_narc = custom_target('fr_script.narc', output: [ 'fr_script.narc', - 'fr_script.naix.h', + 'fr_script.naix', ], input: [ script_bin_gen.process(files( @@ -29,10 +28,11 @@ fr_script_narc = custom_target('fr_script.narc', ), extra_args: ['--out-dir', fr_script_private_dir]), ], command: [ - narc_exe, 'create', - '--naix', - '--order', files('fr_script.order'), - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('fr_script.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) diff --git a/res/field/lighting/meson.build b/res/field/lighting/meson.build index 3b5c61444b..7128dba296 100644 --- a/res/field/lighting/meson.build +++ b/res/field/lighting/meson.build @@ -20,8 +20,6 @@ lighting_data_newline_srcs = lighting_txt_gen.process(files( ], ) -lighting_data_order = files('lighting_sets.order') - lighting_narc = custom_target('lighting.narc', output: [ 'lighting.narc', @@ -30,14 +28,14 @@ lighting_narc = custom_target('lighting.narc', input: [ lighting_data_srcs, lighting_data_newline_srcs, - lighting_data_order ], depends: [ py_consts_generators ], command: [ - narc_exe, 'create', - '--naix', - '--order', lighting_data_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('lighting_sets.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ] ) diff --git a/res/field/maps/data/meson.build b/res/field/maps/data/meson.build index bea62f2bd7..2b320397cc 100644 --- a/res/field/maps/data/meson.build +++ b/res/field/maps/data/meson.build @@ -667,21 +667,18 @@ map_data_files = copy_gen.process(files( 'map_data_665.bin' )) -map_data_order = files('map_data.order') map_data_narc = custom_target('land_data.narc', output: [ 'land_data.narc', ], - input: [ - map_data_files, - map_data_order, - ], + input: map_data_files, command: [ - narc_exe, 'create', - '--order', map_data_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--files-from', files('map_data.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += map_data_narc diff --git a/res/field/maps/texture_sets/meson.build b/res/field/maps/texture_sets/meson.build index 0bd3b7924f..e34cb47056 100644 --- a/res/field/maps/texture_sets/meson.build +++ b/res/field/maps/texture_sets/meson.build @@ -80,23 +80,20 @@ map_texture_set_files = map_texture_set_gen.process(files( 'map_texture_set_073.nsbtx' )) -map_texture_set_order = files('map_texture_sets.order') map_texture_set_narc = custom_target('map_tex_set.narc', output: [ 'map_tex_set.narc', 'map_tex_set.naix', ], - input: [ - map_texture_set_files, - map_texture_set_order, - ], + input: map_texture_set_files, command: [ - narc_exe, 'create', - '--naix', - '--order', map_texture_set_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('map_texture_sets.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += map_texture_set_narc diff --git a/res/field/matrices/meson.build b/res/field/matrices/meson.build index bff61ce26b..9d5616b785 100644 --- a/res/field/matrices/meson.build +++ b/res/field/matrices/meson.build @@ -3,7 +3,6 @@ matrix_bin_gen = generator( arguments: [ '@INPUT@', '@OUTPUT@', ], output: '@BASENAME@', depends: [ py_consts_generators ], - ) matrix_data_srcs = files( @@ -298,22 +297,21 @@ matrix_data_srcs = files( 'map_matrix_288.json' ) -matrix_data_order = files('map_matrices.order') - map_matrix_narc = custom_target('map_matrix.narc', - output: 'map_matrix.narc', - input: [ - matrix_bin_gen.process(matrix_data_srcs, env: jsoncnv_env), - matrix_data_order + output: [ + 'map_matrix.narc', + 'map_matrix.naix', ], + input: matrix_bin_gen.process(matrix_data_srcs, env: jsoncnv_env), depends: [ py_consts_generators ], command: [ - narc_exe, 'create', - '--naix', - '--order', matrix_data_order, - '--output', '@OUTPUT@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('map_matrices.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += map_matrix_narc diff --git a/res/field/props/animations/meson.build b/res/field/props/animations/meson.build index 0e4b37edb3..15f8974562 100644 --- a/res/field/props/animations/meson.build +++ b/res/field/props/animations/meson.build @@ -99,21 +99,16 @@ prop_animation_files = copy_gen.process(files( 'prop_animation_097.nsbtp', )) -prop_animation_order = files('prop_animations.order') prop_animation_narc = custom_target('prop_animations.narc', - output: [ - 'prop_animations.narc', - ], - input: [ - prop_animation_files, - prop_animation_order, - ], + output: 'prop_animations.narc', + input: prop_animation_files, command: [ - narc_exe, 'create', - '--order', prop_animation_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--files-from', files('prop_animations.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += prop_animation_narc diff --git a/res/field/props/model_sets/meson.build b/res/field/props/model_sets/meson.build index 99bd3730b9..876abd24bf 100644 --- a/res/field/props/model_sets/meson.build +++ b/res/field/props/model_sets/meson.build @@ -1,7 +1,8 @@ prop_model_set_bin_gen = generator( prop_model_set_py, arguments: [ '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', ], - output: '@BASENAME@' + output: '@BASENAME@', + depends: [ py_consts_generators, map_prop_model_narc[0] ], ) prop_model_set_data_srcs = files( @@ -78,33 +79,25 @@ prop_model_set_data_srcs = files( 'prop_model_set_070.json' ) -prop_model_set_data_order = files('prop_model_sets.order') - prop_model_set_narc = custom_target('prop_model_sets.narc', output: [ 'prop_model_sets.narc', 'prop_model_sets.naix', ], - input: [ - prop_model_set_bin_gen.process(prop_model_set_data_srcs, - env: jsoncnv_env, - extra_args: [ - '--map-prop-model-naix', map_prop_model_narc[1].full_path() + '.h', - ], - ), - prop_model_set_data_order - ], - depends: [ - py_consts_generators, - map_prop_model_narc - ], + input: prop_model_set_bin_gen.process(prop_model_set_data_srcs, + env: jsoncnv_env, + extra_args: [ + '--map-prop-model-naix', map_prop_model_narc[1].full_path(), + ], + ), command: [ - narc_exe, 'create', - '--naix', - '--order', prop_model_set_data_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('prop_model_sets.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += prop_model_set_narc diff --git a/res/field/props/models/meson.build b/res/field/props/models/meson.build index f0101304e3..1d7f307bb8 100644 --- a/res/field/props/models/meson.build +++ b/res/field/props/models/meson.build @@ -591,23 +591,20 @@ map_prop_model_files = copy_gen.process(files( 'prop_model_589.nsbmd', )) -map_prop_model_order = files('map_prop_models.order') map_prop_model_narc = custom_target('prop_models.narc', output: [ 'prop_models.narc', 'prop_models.naix', ], - input: [ - map_prop_model_files, - map_prop_model_order, - ], + input: map_prop_model_files, command: [ - narc_exe, 'create', - '--naix', - '--order', map_prop_model_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('map_prop_models.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += map_prop_model_narc diff --git a/res/field/props/texture_sets/meson.build b/res/field/props/texture_sets/meson.build index e6be144569..1e3c340ea3 100644 --- a/res/field/props/texture_sets/meson.build +++ b/res/field/props/texture_sets/meson.build @@ -72,21 +72,16 @@ prop_texture_set_files = copy_gen.process(files( 'prop_texture_set_070.nsbtx' )) -prop_texture_set_order = files('prop_texture_sets.order') prop_texture_set_narc = custom_target('prop_texture_sets.narc', - output: [ - 'prop_texture_sets.narc', - ], - input: [ - prop_texture_set_files, - prop_texture_set_order, - ], + output: 'prop_texture_sets.narc', + input: prop_texture_set_files, command: [ - narc_exe, 'create', - '--order', prop_texture_set_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--files-from', files('prop_texture_sets.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += prop_texture_set_narc diff --git a/res/field/scripts/meson.build b/res/field/scripts/meson.build index 4840b95b36..b500fb6df2 100644 --- a/res/field/scripts/meson.build +++ b/res/field/scripts/meson.build @@ -1159,22 +1159,21 @@ scr_seq_files = files( 'scripts_route_230.s', ) -scr_seq_narc_order = files('scripts.order') - scr_seq_narc = custom_target('scr_seq.narc', output: [ 'scr_seq.narc', - 'scr_seq.naix.h', + 'scr_seq.naix', ], input: field_script_bin_gen.process( scr_seq_files, extra_args: ['--depfile', '--out-dir', scr_seq_private_dir] ), command: [ - narc_exe, 'create', - '--naix', - '--order', scr_seq_narc_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('scripts.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) diff --git a/res/field/trades/meson.build b/res/field/trades/meson.build index bd738056ba..f397e22fe8 100644 --- a/res/field/trades/meson.build +++ b/res/field/trades/meson.build @@ -14,17 +14,16 @@ foreach npc_trade: npc_trades_consts npc_trades_files += files(npc_trade.to_lower() + '.json') endforeach -npc_trades_order = files('npc_trades.order') npc_trades_narc = custom_target('fld_trade.narc', output: 'fld_trade.narc', input: npc_trades_bin_gen.process(npc_trades_files, env: jsoncnv_env), - depends: [ py_consts_generators ], command: [ - narc_exe, 'create', - '--order', npc_trades_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--files-from', files('npc_trades.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += npc_trades_narc diff --git a/res/fonts/meson.build b/res/fonts/meson.build index 65e4df4845..2944317fc7 100644 --- a/res/fonts/meson.build +++ b/res/fonts/meson.build @@ -1,111 +1,52 @@ -fonts = { - 'font_system.NFGR': files('font_system.png', 'font_system.json'), - 'font_message.NFGR': files('font_message.png', 'font_message.json'), - 'font_subscreen.NFGR': files('font_subscreen.png', 'font_subscreen.json'), - 'font_unown.NFGR': files('font_unown.png', 'font_unown.json'), -} - nfgr_gen = generator(nitrogfx_exe, - arguments: [ '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@', ], + arguments: [ '@INPUT@', '@OUTPUT@', '-metadata', '@CURRENT_SOURCE_DIR@/@BASENAME@.json', ], output: '@BASENAME@.NFGR', ) -font_nfgrs = [] -foreach target, inputs: fonts - font_nfgrs += custom_target(target, - output: target, - input: inputs, - command: [ - nitrogfx_exe, - '@INPUT0@', - '@OUTPUT@', - '-metadata', '@INPUT1@', - ] - ) - -endforeach - -font_special_chars_png = files('font_special_chars.png') -font_special_chars_ncgr = custom_target('font_special_chars.NCGR', - output: 'font_special_chars.NCGR', - input: font_special_chars_png, - command: [ - nitrogfx_exe, - '@INPUT@', - '@OUTPUT@', - '-sopc', - '-version101', - ], -) -font_special_chars_ncgr_lz = custom_target('font_special_chars.NCGR.lz', - output: 'font_special_chars.NCGR.lz', - input: font_special_chars_ncgr, - command: [ - nitrogfx_exe, - '@INPUT@', - '@OUTPUT@', - ], -) -font_nclr = custom_target('font.NCLR', +# Meson does not allow us to use a generator for a target like this, where we +# want to name the output quite differently from the input file. So, we use a +# custom target, then copy it into the private directory for packing. +font_base_nclr = custom_target('font.NCLR', output: 'font.NCLR', - input: font_special_chars_png, - command: [ - nitrogfx_exe, - '@INPUT@', - '@OUTPUT@', - '-bitdepth', '4', - '-nopad', - '-pcmp', - ], + input: files('font_special_chars.png'), + command: [ nitrogfx_exe, '@INPUT@', '@OUTPUT@', '-bitdepth', '4', '-nopad', '-pcmp' ], ) -screen_indicators_png = files('screen_indicators.png') -screen_indicators_ncgr = custom_target('screen_indicators.NCGR', - output: 'screen_indicators.NCGR', - input: screen_indicators_png, - command: [ - nitrogfx_exe, - '@INPUT@', - '@OUTPUT@', - '-sopc', - '-version101', - ], -) -screen_indicators_nclr = custom_target('screen_indicators.NCLR', - output: 'screen_indicators.NCLR', - input: screen_indicators_png, - command: [ - nitrogfx_exe, - '@INPUT@', - '@OUTPUT@', - '-bitdepth', '4', - ], -) - -current_build_dir = meson.current_build_dir() -pl_font_order = files('pl_font.order') -pl_font_ignore = files('pl_font.ignore') pl_font_narc = custom_target('pl_font.narc', output: [ 'pl_font.narc', - 'pl_font.naix.h', + 'pl_font.naix', ], input: [ - font_nfgrs, - font_special_chars_ncgr_lz, - font_nclr, - screen_indicators_ncgr, - screen_indicators_nclr, - pl_font_order, - pl_font_ignore, + nfgr_gen.process( + files( + 'font_system.png', + 'font_message.png', + 'font_subscreen.png', + 'font_unown.png', + ) + ), + ncgr_lz_gen.process( + files('font_special_chars.png'), + extra_args: [ '-sopc', '-version101' ], + ), + ncgr_gen.process( + files('screen_indicators.png'), + extra_args: [ '-sopc', '-version101' ], + ), + nclr_gen.process( + files('screen_indicators.png'), + extra_args: [ '-bitdepth', '4' ], + ), + copy_gen.process(font_base_nclr), ], command: [ - narc_exe, 'create', - '--naix', - '--order', pl_font_order, - '--ignore', pl_font_ignore, - '--output', '@OUTPUT0@', - '@OUTDIR@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('pl_font.order'), + '--file', '@OUTPUT0@', + '@PRIVATE_DIR@', ], ) diff --git a/res/fonts/pl_font.ignore b/res/fonts/pl_font.ignore deleted file mode 100644 index e93e4aee57..0000000000 --- a/res/fonts/pl_font.ignore +++ /dev/null @@ -1,5 +0,0 @@ -font_special_chars.NCGR -*.narc -*.naix -*.h -*.4bpp diff --git a/res/graphics/bag/meson.build b/res/graphics/bag/meson.build index feecff084d..a236539726 100644 --- a/res/graphics/bag/meson.build +++ b/res/graphics/bag/meson.build @@ -111,12 +111,9 @@ sprites_ncgr_8bpp = ncgr_gen.process( ) bag_graphics_narc = custom_target('bag_graphics.narc', - command: [ - narc_exe, 'create', - '--naix', - '--order', files('bag_graphics.order'), - '--output', '@OUTPUT0@', - '@PRIVATE_DIR@', + output: [ + 'bag_graphics.narc', + 'bag_graphics.naix', ], input: [ tilemaps_nscr, @@ -131,9 +128,13 @@ bag_graphics_narc = custom_target('bag_graphics.narc', sprites_ncgr_cell, sprites_ncgr_8bpp, ], - output: [ - 'bag_graphics.narc', - 'bag_graphics.naix.h', + command: [ + nitroarc_exe, + '--create', + '--index', + '--files-from', files('bag_graphics.order'), + '--file', '@OUTPUT0@', + '@PRIVATE_DIR@', ], ) diff --git a/res/graphics/battle/moves/meson.build b/res/graphics/battle/moves/meson.build index c6a1b3a9b2..800fa03af7 100644 --- a/res/graphics/battle/moves/meson.build +++ b/res/graphics/battle/moves/meson.build @@ -14,10 +14,10 @@ anim_ncer_order = files(anim_ncer_basename + '.order') anim_nanr_order = files(anim_nanr_basename + '.order') anim_nclr_order = files(anim_nclr_basename + '.order') -anim_ncgr_naix = anim_ncgr_basename + '.naix.h' -anim_ncer_naix = anim_ncer_basename + '.naix.h' -anim_nanr_naix = anim_nanr_basename + '.naix.h' -anim_nclr_naix = anim_nclr_basename + '.naix.h' +anim_ncgr_naix = anim_ncgr_basename + '.naix' +anim_ncer_naix = anim_ncer_basename + '.naix' +anim_nanr_naix = anim_nanr_basename + '.naix' +anim_nclr_naix = anim_nclr_basename + '.naix' pngs = files( 'surf.png', @@ -267,12 +267,13 @@ anim_ncgr_narc_files = custom_target(anim_ncgr_narc, no_cell_ncgr_lz_files, ], command: [ - narc_exe, 'create', - '--naix', - '--order', anim_ncgr_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', anim_ncgr_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) anim_ncer_narc_files = custom_target(anim_ncer_narc, output: [ @@ -283,12 +284,13 @@ anim_ncer_narc_files = custom_target(anim_ncer_narc, ncer_lz_files, ], command: [ - narc_exe, 'create', - '--naix', - '--order', anim_ncer_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', anim_ncer_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) anim_nanr_narc_files = custom_target(anim_nanr_narc, output: [ @@ -299,12 +301,13 @@ anim_nanr_narc_files = custom_target(anim_nanr_narc, nanr_lz_files, ], command: [ - narc_exe, 'create', - '--naix', - '--order', anim_nanr_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', anim_nanr_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) anim_nclr_narc_files = custom_target(anim_nclr_narc, output: [ @@ -319,12 +322,13 @@ anim_nclr_narc_files = custom_target(anim_nclr_narc, no_cell_nclr_files, ], command: [ - narc_exe, 'create', - '--naix', - '--order', anim_nclr_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', anim_nclr_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += anim_ncgr_narc_files diff --git a/res/graphics/diploma/meson.build b/res/graphics/diploma/meson.build index 8940576375..302b79a913 100644 --- a/res/graphics/diploma/meson.build +++ b/res/graphics/diploma/meson.build @@ -25,25 +25,24 @@ diploma_nscrs = copy_gen.process(files( 'national_dex_blank.NSCR', )) -diploma_order = files('diploma.order') diploma_narc = custom_target('diploma.narc', output: [ 'diploma.narc', - 'diploma.naix.h', + 'diploma.naix', ], input: [ diploma_ncgrs, diploma_nclrs, diploma_nscrs, - diploma_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', diploma_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('diploma.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += diploma_narc diff --git a/res/graphics/item_icons/meson.build b/res/graphics/item_icons/meson.build index e78906b9b8..ccb16917ad 100644 --- a/res/graphics/item_icons/meson.build +++ b/res/graphics/item_icons/meson.build @@ -744,7 +744,7 @@ item_icon_order = files('item_icon.order') item_icon_narc = custom_target('item_icon.narc', output: [ 'item_icon.narc', - 'item_icon.naix.h', + 'item_icon.naix', ], input: [ item_icon_ncgrs, @@ -753,15 +753,15 @@ item_icon_narc = custom_target('item_icon.narc', copy_gen.process(item_icon_unused_nclrs), item_icon_nanrs, item_icon_ncers, - item_icon_order ], command: [ - narc_exe, 'create', - '--naix', - '--order', item_icon_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('item_icon.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += item_icon_narc diff --git a/res/graphics/main_menu/meson.build b/res/graphics/main_menu/meson.build index ec23e445a2..13fecaae1e 100644 --- a/res/graphics/main_menu/meson.build +++ b/res/graphics/main_menu/meson.build @@ -138,12 +138,10 @@ main_menu_ncer = ncer_lz_gen.process( extra_args: ['-nopad'], ) -main_menu_graphics_order = files('main_menu_graphics.order') - main_menu_graphics_narc = custom_target('main_menu_graphics.narc', output: [ 'main_menu_graphics.narc', - 'main_menu_graphics.naix.h', + 'main_menu_graphics.naix', ], input: [ main_menu_palettes_nclr, @@ -157,14 +155,14 @@ main_menu_graphics_narc = custom_target('main_menu_graphics.narc', main_menu_tilemaps_nscr, main_menu_nanr, main_menu_ncer, - main_menu_graphics_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', main_menu_graphics_order, - '--output', '@OUTPUT0@', - '@PRIVATE_DIR@' + nitroarc_exe, + '--create', + '--index', + '--files-from', files('main_menu_graphics.order'), + '--file', '@OUTPUT0@', + '@PRIVATE_DIR@', ], ) diff --git a/res/graphics/mining/animations/meson.build b/res/graphics/mining/animations/meson.build index 2d59c9a9f5..c615778e15 100644 --- a/res/graphics/mining/animations/meson.build +++ b/res/graphics/mining/animations/meson.build @@ -33,11 +33,10 @@ mining_animations_ncers = ncer_gen.process(files('crack_end_cell.json', 'animati mining_animations_nanrs = nanr_gen.process(files('crack_end_anim.json', 'animations_anim.json')) -mining_animations_order = files('animations.order') mining_animations_narc = custom_target('animations.narc', output: [ 'animations.narc', - 'animations.naix.h', + 'animations.naix', ], input: [ mining_animations_ncgrs_converted, @@ -48,12 +47,13 @@ mining_animations_narc = custom_target('animations.narc', mining_animations_nanrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', mining_animations_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('animations.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += mining_animations_narc diff --git a/res/graphics/mining/interface/meson.build b/res/graphics/mining/interface/meson.build index 968b8acdc1..68503d13b9 100644 --- a/res/graphics/mining/interface/meson.build +++ b/res/graphics/mining/interface/meson.build @@ -18,11 +18,10 @@ mining_interface_nclrs = nclr_gen.process(mining_interface_pngs, mining_interface_nscrs = copy_gen.process(files('interface.NSCR')) -mining_interface_order = files('interface.order') mining_interface_narc = custom_target('interface.narc', output: [ 'interface.narc', - 'interface.naix.h', + 'interface.naix', ], input: [ mining_interface_ncgrs, @@ -30,12 +29,13 @@ mining_interface_narc = custom_target('interface.narc', mining_interface_nscrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', mining_interface_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('interface.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += mining_interface_narc diff --git a/res/graphics/mining/objects/meson.build b/res/graphics/mining/objects/meson.build index f357ae354a..3bd3e9cde1 100644 --- a/res/graphics/mining/objects/meson.build +++ b/res/graphics/mining/objects/meson.build @@ -164,11 +164,10 @@ mining_objects_nclrs_pals = nclr_gen.process(mining_objects_pals, ], ) -mining_objects_order = files('objects.order') mining_objects_narc = custom_target('objects.narc', output: [ 'objects.narc', - 'objects.naix.h', + 'objects.naix', ], input: [ mining_objects_ncgrs_converted, @@ -181,12 +180,13 @@ mining_objects_narc = custom_target('objects.narc', mining_objects_nclrs_pals, ], command: [ - narc_exe, 'create', - '--naix', - '--order', mining_objects_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('objects.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += mining_objects_narc diff --git a/res/graphics/move_tutor/meson.build b/res/graphics/move_tutor/meson.build index 6bd11589aa..957e6d50e6 100644 --- a/res/graphics/move_tutor/meson.build +++ b/res/graphics/move_tutor/meson.build @@ -45,12 +45,10 @@ move_tutor_pals = nclr_gen.process( move_tutor_nscr = copy_gen.process(files('move_tutor_background.NSCR')) -move_tutor_order = files('move_tutor.order') - move_tutor_narc = custom_target('move_tutor.narc', output: [ 'move_tutor.narc', - 'move_tutor.naix.h', + 'move_tutor.naix', ], input: [ move_tutor_tiles, @@ -61,12 +59,13 @@ move_tutor_narc = custom_target('move_tutor.narc', move_tutor_nscr, ], command: [ - narc_exe, 'create', - '--naix', - '--order', move_tutor_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('move_tutor.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += move_tutor_narc diff --git a/res/graphics/naming_screen/meson.build b/res/graphics/naming_screen/meson.build index 1a80023463..62d26e5198 100644 --- a/res/graphics/naming_screen/meson.build +++ b/res/graphics/naming_screen/meson.build @@ -76,12 +76,10 @@ naming_screen_nscr_lzs = lz_gen.process(naming_screen_nscrs, ] ) -naming_screen_order = files('naming_screen.order') - naming_screen_narc = custom_target('namein.narc', output: [ 'namein.narc', - 'namein.naix.h', + 'namein.naix', ], input: [ naming_screen_ncgr_lzs, @@ -90,15 +88,15 @@ naming_screen_narc = custom_target('namein.narc', naming_screen_ncer_lzs, naming_screen_nanr_lzs, naming_screen_nscr_lzs, - naming_screen_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', naming_screen_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('naming_screen.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += naming_screen_narc diff --git a/res/graphics/options_menu/meson.build b/res/graphics/options_menu/meson.build index 245abe1384..5e7995e350 100644 --- a/res/graphics/options_menu/meson.build +++ b/res/graphics/options_menu/meson.build @@ -7,25 +7,24 @@ tiles_nclr = nclr_gen.process(tiles_png, ) tilemap_nscr = copy_gen.process(files('tilemap.bin')) -config_gra_order = files('config_gra.order') config_gra_narc = custom_target('config_gra.narc', output: [ 'config_gra.narc', - 'config_gra.naix.h', + 'config_gra.naix', ], input: [ tiles_ncgr, tiles_nclr, tilemap_nscr, - config_gra_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', config_gra_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('config_gra.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += config_gra_narc diff --git a/res/graphics/party_menu/form_changes/meson.build b/res/graphics/party_menu/form_changes/meson.build index 103a9c563b..1652863527 100644 --- a/res/graphics/party_menu/form_changes/meson.build +++ b/res/graphics/party_menu/form_changes/meson.build @@ -3,23 +3,20 @@ form_change_effects_files = files( 'shaymin.spa', ) -form_change_effects_order = files('form_change_effects.order') - form_change_effects_narc = custom_target('form_change_effects_narc', output: [ 'form_change_effects.narc', - 'form_change_effects.naix.h', + 'form_change_effects.naix', ], - input: copy_gen.process( - form_change_effects_files, - ), + input: copy_gen.process(form_change_effects_files), command: [ - narc_exe, 'create', - '--naix', - '--order', form_change_effects_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('form_change_effects.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += form_change_effects_narc diff --git a/res/graphics/party_menu/meson.build b/res/graphics/party_menu/meson.build index 9a61c9523e..80bb788fd9 100644 --- a/res/graphics/party_menu/meson.build +++ b/res/graphics/party_menu/meson.build @@ -3,7 +3,7 @@ subdir('form_changes') party_menu_narc = custom_target('party_menu_graphics.narc', output: [ 'party_menu_graphics.narc', - 'party_menu_graphics.naix.h', + 'party_menu_graphics.naix', ], input: [ @@ -69,11 +69,13 @@ party_menu_narc = custom_target('party_menu_graphics.narc', ], command: [ - narc_exe, 'create', '--naix', - '--order', files('party_menu_graphics.order'), - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('party_menu_graphics.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += party_menu_narc diff --git a/res/graphics/poffin_case/feeding_cutscene/meson.build b/res/graphics/poffin_case/feeding_cutscene/meson.build index 77ea71ae45..66be8b9300 100644 --- a/res/graphics/poffin_case/feeding_cutscene/meson.build +++ b/res/graphics/poffin_case/feeding_cutscene/meson.build @@ -36,11 +36,10 @@ nscrs = copy_gen.process(files( 'bottom_screen_tilemap.NSCR', )) -cutscene_order = files('cutscene.order') poffin_cutscene_narc = custom_target('cutscene.narc', output: [ 'cutscene.narc', - 'cutscene.naix.h', + 'cutscene.naix', ], input: [ top_nclr, @@ -50,12 +49,13 @@ poffin_cutscene_narc = custom_target('cutscene.narc', nscrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', cutscene_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('cutscene.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += poffin_cutscene_narc diff --git a/res/graphics/poffin_case/meson.build b/res/graphics/poffin_case/meson.build index 5f56bb5df0..19a33ef522 100644 --- a/res/graphics/poffin_case/meson.build +++ b/res/graphics/poffin_case/meson.build @@ -67,11 +67,10 @@ tilemaps = copy_gen.process(files( 'sub_tilemap.NSCR', )) -poffin_case_order = files('poffin_case.order') poffin_case_narc = custom_target('poru_gra.narc', output: [ 'poru_gra.narc', - 'poru_gra.naix.h', + 'poru_gra.naix', ], input: [ nclr, @@ -83,12 +82,13 @@ poffin_case_narc = custom_target('poru_gra.narc', tilemaps, ], command: [ - narc_exe, 'create', - '--naix', - '--order', poffin_case_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('poffin_case.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += poffin_case_narc naix_headers += poffin_case_narc[1] diff --git a/res/graphics/pokedex/meson.build b/res/graphics/pokedex/meson.build index 5efdac0bac..aff11dbc87 100644 --- a/res/graphics/pokedex/meson.build +++ b/res/graphics/pokedex/meson.build @@ -265,11 +265,10 @@ palettes_nclr = nclr_gen.process(palettes_pal, ], ) -pokedex_order = files('pokedex.order') pokedex_graphics_narc = custom_target('zukan.narc', output: [ 'zukan.narc', - 'zukan.naix.h', + 'zukan.naix', ], input: [ tiles_ncgr_4bpp, @@ -283,15 +282,15 @@ pokedex_graphics_narc = custom_target('zukan.narc', sprites_ncer, sprites_nanr, palettes_nclr, - pokedex_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', pokedex_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('pokedex.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += pokedex_graphics_narc diff --git a/res/graphics/pokemon_summary_screen/meson.build b/res/graphics/pokemon_summary_screen/meson.build index 4b1feab958..b85789d845 100644 --- a/res/graphics/pokemon_summary_screen/meson.build +++ b/res/graphics/pokemon_summary_screen/meson.build @@ -209,11 +209,10 @@ palettes_nclr_8bpp = nclr_gen.process(palettes_pal_8bpp, ], ) -pokemon_summary_screen_order = files('pokemon_summary_screen.order') pokemon_summary_screen_narc = custom_target('pl_pst_gra.narc', output: [ 'pl_pst_gra.narc', - 'pl_pst_gra.naix.h', + 'pl_pst_gra.naix', ], input: [ tiles_ncgr, @@ -224,15 +223,15 @@ pokemon_summary_screen_narc = custom_target('pl_pst_gra.narc', sprites_nanr, palettes_nclr_4bpp, palettes_nclr_8bpp, - pokemon_summary_screen_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', pokemon_summary_screen_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('pokemon_summary_screen.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += pokemon_summary_screen_narc diff --git a/res/graphics/poketch/meson.build b/res/graphics/poketch/meson.build index 4e26eea9ee..949203bb70 100644 --- a/res/graphics/poketch/meson.build +++ b/res/graphics/poketch/meson.build @@ -216,12 +216,10 @@ poketch_ncgrs = copy_gen.process(files( 'stopwatch.NCGR.lz', )) -poketch_order = files('poketch.order') - poketch_narc = custom_target('poketch_narc', output: [ 'poketch.narc', - 'poketch.naix.h', + 'poketch.naix', ], input: [ poketch_graphics, @@ -238,12 +236,13 @@ poketch_narc = custom_target('poketch_narc', poketch_screen_palette_dupe, ], command: [ - narc_exe, 'create', - '--naix', - '--order', poketch_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('poketch.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += poketch_narc diff --git a/res/graphics/scroll_prompts/meson.build b/res/graphics/scroll_prompts/meson.build index f00e89ae4f..3a52bc7635 100644 --- a/res/graphics/scroll_prompts/meson.build +++ b/res/graphics/scroll_prompts/meson.build @@ -9,26 +9,25 @@ scroll_prompts_nclr = nclr_gen.process(scroll_prompts_png, scroll_prompts_ncer = ncer_gen.process(files('scroll_prompts_cell.json')) scroll_prompts_nanr = nanr_gen.process(files('scroll_prompts_anim.json')) -fld_comact_order = files('fld_comact.order') fld_comact_narc = custom_target('fld_comact.narc', output: [ 'fld_comact.narc', - 'fld_comact.naix.h', + 'fld_comact.naix', ], input: [ scroll_prompts_ncgr, scroll_prompts_nclr, scroll_prompts_ncer, scroll_prompts_nanr, - fld_comact_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', fld_comact_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('fld_comact.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += fld_comact_narc diff --git a/res/graphics/shop_menu/meson.build b/res/graphics/shop_menu/meson.build index 6292156f27..f5b9b2b0da 100644 --- a/res/graphics/shop_menu/meson.build +++ b/res/graphics/shop_menu/meson.build @@ -42,11 +42,10 @@ palettes_nclr = nclr_gen.process(palettes_pal, ], ) -shop_gra_order = files('shop_gra.order') shop_gra_narc = custom_target('shop_gra.narc', output: [ 'shop_gra.narc', - 'shop_gra.naix.h', + 'shop_gra.naix', ], input: [ tiles_ncgr, @@ -55,15 +54,15 @@ shop_gra_narc = custom_target('shop_gra.narc', sprites_ncer, sprites_nanr, palettes_nclr, - shop_gra_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', shop_gra_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('shop_gra.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += shop_gra_narc diff --git a/res/graphics/signposts/meson.build b/res/graphics/signposts/meson.build index 864f9a9fee..95ac8b6828 100644 --- a/res/graphics/signposts/meson.build +++ b/res/graphics/signposts/meson.build @@ -67,25 +67,23 @@ field_board_nclrs = nclr_gen.process(field_board_pals, ] ) -field_board_order = files('field_board.order') - field_board_narc = custom_target('field_board.narc', output: [ 'field_board.narc', - 'field_board.naix.h', + 'field_board.naix', ], input: [ field_board_ncgrs, field_board_nclrs, - field_board_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', field_board_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('field_board.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += field_board_narc diff --git a/res/graphics/start_menu/meson.build b/res/graphics/start_menu/meson.build index 9ee4dc3cec..07effb13af 100644 --- a/res/graphics/start_menu/meson.build +++ b/res/graphics/start_menu/meson.build @@ -38,7 +38,7 @@ start_menu_order = files('start_menu.order') start_menu_narc = custom_target('start_menu.narc', output: [ 'start_menu.narc', - 'start_menu.naix.h', + 'start_menu.naix', ], input: [ ncgrs, @@ -47,12 +47,13 @@ start_menu_narc = custom_target('start_menu.narc', nclrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', start_menu_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('start_menu.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += start_menu_narc diff --git a/res/graphics/title_screen/meson.build b/res/graphics/title_screen/meson.build index a9ab53459c..2ca6df03d7 100644 --- a/res/graphics/title_screen/meson.build +++ b/res/graphics/title_screen/meson.build @@ -79,7 +79,7 @@ titledemo_order = files('titledemo.order') titledemo_narc = custom_target('titledemo.narc', output: [ 'titledemo.narc', - 'titledemo.naix.h', + 'titledemo.naix', ], input: [ ncgrs_4bpp, @@ -89,19 +89,19 @@ titledemo_narc = custom_target('titledemo.narc', nclrs_explicit, ncgrs_explicit, tilemaps, - titledemo_order, models, anims, tex_anims, mat_anims, ], command: [ - narc_exe, 'create', - '--naix', - '--order', titledemo_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('titledemo.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += titledemo_narc diff --git a/res/graphics/town_map/meson.build b/res/graphics/town_map/meson.build index 2e681064aa..0177221af5 100644 --- a/res/graphics/town_map/meson.build +++ b/res/graphics/town_map/meson.build @@ -156,12 +156,9 @@ bottom_screen_bg_nclr = custom_target('bottom_screen_bg_nclr', ) town_map_graphics_narc = custom_target('town_map_graphics.narc', - command: [ - narc_exe, 'create', - '--naix', - '--order', files('town_map_graphics.order'), - '--output', '@OUTPUT0@', - '@PRIVATE_DIR@', + output: [ + 'town_map_graphics.narc', + 'town_map_graphics.naix', ], input: [ tilemaps_nscr, @@ -174,9 +171,13 @@ town_map_graphics_narc = custom_target('town_map_graphics.narc', copy_gen.process(top_screen_sprites_nclr), copy_gen.process(bottom_screen_bg_nclr), ], - output: [ - 'town_map_graphics.narc', - 'town_map_graphics.naix.h', + command: [ + nitroarc_exe, + '--create', + '--index', + '--files-from', files('town_map_graphics.order'), + '--file', '@OUTPUT0@', + '@PRIVATE_DIR@', ], ) diff --git a/res/graphics/trap_effects/meson.build b/res/graphics/trap_effects/meson.build index a48eaf6012..016ac526f7 100644 --- a/res/graphics/trap_effects/meson.build +++ b/res/graphics/trap_effects/meson.build @@ -116,7 +116,7 @@ trap_effects_order = files('trap_effects.order') trap_effects_narc = custom_target('trap_effects.narc', output: [ 'trap_effects.narc', - 'trap_effects.naix.h', + 'trap_effects.naix', ], input: [ trap_effect_boulder_ncgrs, @@ -128,12 +128,13 @@ trap_effects_narc = custom_target('trap_effects.narc', trap_effect_copied, ], command: [ - narc_exe, 'create', - '--naix', - '--order', trap_effects_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('trap_effects.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += trap_effects_narc diff --git a/res/graphics/underground_map_transition/meson.build b/res/graphics/underground_map_transition/meson.build index 281b7581b2..c55ae0525f 100644 --- a/res/graphics/underground_map_transition/meson.build +++ b/res/graphics/underground_map_transition/meson.build @@ -40,11 +40,10 @@ nclrs_8bpp = nclr_gen.process(pngs_8bpp, ncers = ncer_gen.process(cells) nanrs = nanr_gen.process(anims) -underground_map_transition_order = files('underground_map_transition.order') underground_map_transition_narc = custom_target('underground_map_transition.narc', output: [ 'underground_map_transition.narc', - 'underground_map_transition.naix.h', + 'underground_map_transition.naix', ], input: [ ncgrs_4bpp, @@ -55,12 +54,13 @@ underground_map_transition_narc = custom_target('underground_map_transition.narc nanrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', underground_map_transition_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('underground_map_transition.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += underground_map_transition_narc diff --git a/res/graphics/underground_top_screen/meson.build b/res/graphics/underground_top_screen/meson.build index acedbef849..6f00595f21 100644 --- a/res/graphics/underground_top_screen/meson.build +++ b/res/graphics/underground_top_screen/meson.build @@ -31,11 +31,10 @@ nanrs = nanr_gen.process(anims) nscrs = copy_gen.process(files('background.NSCR')) -underground_top_screen_order = files('underground_top_screen.order') underground_top_screen_narc = custom_target('underground_top_screen.narc', output: [ 'underground_top_screen.narc', - 'underground_top_screen.naix.h', + 'underground_top_screen.naix', ], input: [ ncgrs, @@ -46,12 +45,13 @@ underground_top_screen_narc = custom_target('underground_top_screen.narc', nscrs, ], command: [ - narc_exe, 'create', - '--naix', - '--order', underground_top_screen_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('underground_top_screen.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += underground_top_screen_narc diff --git a/res/graphics/windows/meson.build b/res/graphics/windows/meson.build index 55b575f24f..716aa46708 100644 --- a/res/graphics/windows/meson.build +++ b/res/graphics/windows/meson.build @@ -62,12 +62,10 @@ pl_winframe_nclrs = nclr_gen.process(pl_winframe_pals, pl_winframe_ncers = ncer_gen.process(files('pokemon_preview_cell.json')) pl_winframe_nanrs = nanr_gen.process(files('pokemon_preview_anim.json')) -pl_winframe_order = files('pl_winframe.order') - pl_winframe_narc = custom_target('pl_winframe.narc', output: [ 'pl_winframe.narc', - 'pl_winframe.naix.h', + 'pl_winframe.naix', ], input: [ pl_winframe_ncgrs_sopc_v101, @@ -75,15 +73,15 @@ pl_winframe_narc = custom_target('pl_winframe.narc', pl_winframe_nclrs, pl_winframe_ncers, pl_winframe_nanrs, - pl_winframe_order, ], command: [ - narc_exe, 'create', - '--naix', - '--order', pl_winframe_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('pl_winframe.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += pl_winframe_narc diff --git a/res/pokemon/meson.build b/res/pokemon/meson.build index 2f49bc18b3..1ff4e2b639 100644 --- a/res/pokemon/meson.build +++ b/res/pokemon/meson.build @@ -222,7 +222,7 @@ h_headers += datagen_species_out[12] pl_poke_icon_narc = custom_target('pl_poke_icon.narc', output: [ 'pl_poke_icon.narc', - 'pl_poke_icon.naix.h', + 'pl_poke_icon.naix', ], input: [ icons_shared, @@ -232,7 +232,7 @@ pl_poke_icon_narc = custom_target('pl_poke_icon.narc', command: [ make_pl_poke_icon_py, '--nitrogfx', nitrogfx_exe, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--order-file', files('species_icons.order'), '--shared-dir', '@CURRENT_SOURCE_DIR@/.shared', '--private-dir', '@PRIVATE_DIR@', @@ -250,7 +250,7 @@ pl_pokegra_narc = custom_target('pl_pokegra.narc', command: [ make_pl_pokegra_py, '--nitrogfx', nitrogfx_exe, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -260,7 +260,7 @@ pl_pokegra_narc = custom_target('pl_pokegra.narc', pl_otherpoke_narc = custom_target('pl_otherpoke.narc', output: [ 'pl_otherpoke.narc', - 'pl_otherpoke.naix.h', + 'pl_otherpoke.naix', ], input: [ otherpoke_files, @@ -270,7 +270,7 @@ pl_otherpoke_narc = custom_target('pl_otherpoke.narc', command: [ make_pl_otherpoke_py, '--nitrogfx', nitrogfx_exe, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', '--sprite-entries', '154', @@ -287,7 +287,7 @@ pl_pokezukan_narc = custom_target('pl_pokezukan.narc', depends: [ py_consts_generators ], command: [ make_pl_pokezukan_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -304,7 +304,7 @@ shinzukan_narc = custom_target('shinzukan.narc', depends: [ py_consts_generators ], command: [ make_shinzukan_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -318,7 +318,7 @@ pl_growtbl_narc = custom_target('pl_growtbl.narc', input: pl_growtbl_files, command: [ make_pl_growtbl_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -331,7 +331,7 @@ pokedex_data_narc = custom_target('zukan_data.narc', output: 'zukan_data.narc', command: [ make_pokedex_data_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -347,7 +347,7 @@ pokedex_data_giratina_altered_narc = custom_target('zukan_data_gira.narc', output: 'zukan_data_gira.narc', command: [ make_pokedex_data_py, - '--narc', narc_exe, + '--narc', nitroarc_exe, '--source-dir', '@CURRENT_SOURCE_DIR@', '--private-dir', '@PRIVATE_DIR@', '--output-dir', '@OUTDIR@', @@ -391,7 +391,7 @@ pokefoot_ncgr_lz = ncgr_lz_gen.process( pokefoot_narc = custom_target('pokefoot.narc', output: [ 'pokefoot.narc', - 'pokefoot.naix.h', + 'pokefoot.naix', ], input: [ pokefoot_nclr, @@ -400,10 +400,11 @@ pokefoot_narc = custom_target('pokefoot.narc', pokefoot_ncgr_lz, ], command: [ - narc_exe, 'create', - '--naix', - '--order', pokefoot_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', pokefoot_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) diff --git a/res/pokemon_anims/meson.build b/res/pokemon_anims/meson.build index b8b043ae2e..9e4681125d 100644 --- a/res/pokemon_anims/meson.build +++ b/res/pokemon_anims/meson.build @@ -149,22 +149,21 @@ pokemon_anims_files = files( 'pokemon_anim_script_unk_142.s', ) -pokemon_anims_narc_order = files('pokemon_anims.order') - pokemon_anims_narc = custom_target(pokemon_anims_target_name, output: [ 'pokemon_anims.narc', - 'pokemon_anims.naix.h', + 'pokemon_anims.naix', ], input: script_bin_gen.process( pokemon_anims_files, extra_args: ['--depfile', '--out-dir', pokemon_anims_private_dir] ), command: [ - narc_exe, 'create', - '--naix', - '--order', pokemon_anims_narc_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('pokemon_anims.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) diff --git a/res/prebuilt/data/mmodel/meson.build b/res/prebuilt/data/mmodel/meson.build index b5864950cb..d82edfa5ce 100644 --- a/res/prebuilt/data/mmodel/meson.build +++ b/res/prebuilt/data/mmodel/meson.build @@ -4,10 +4,11 @@ mmodel_narc = custom_target('mmodel.narc', output: 'mmodel.narc', input: mmodel_files_targets, command: [ - narc_exe, 'create', - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--file', '@OUTPUT0@', '@OUTDIR@/mmodel', - ] + ], ) nitrofs_files += mmodel_narc diff --git a/res/text/meson.build b/res/text/meson.build index 170ff971ee..b45d312341 100644 --- a/res/text/meson.build +++ b/res/text/meson.build @@ -160,11 +160,13 @@ text_banks = custom_target('pl_msg.narc', output: 'pl_msg.narc', input: json_to_bin_gen.process(text_bank_files), command: [ - narc_exe, 'create', - '--order', text_banks_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', text_banks_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', - ] + ], ) nitrofs_files += text_banks diff --git a/res/trainers/classes/meson.build b/res/trainers/classes/meson.build index 00dc32b734..2449389a4f 100644 --- a/res/trainers/classes/meson.build +++ b/res/trainers/classes/meson.build @@ -216,7 +216,7 @@ castle_valet_NCGR = ncgr_gen.process(castle_valet_png, trfgra_narc = custom_target('trfgra.narc', output: [ 'trfgra.narc', - 'trfgra.naix.h', + 'trfgra.naix', ], input: [ trainer_front_NCGR, @@ -227,10 +227,11 @@ trfgra_narc = custom_target('trfgra.narc', castle_valet_NCGR, ], command: [ - narc_exe, 'create', - '--naix', - '--order', trfgra_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', trfgra_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) @@ -268,7 +269,7 @@ trainer_back_scan_NCGR = ncgr_gen.process(trainer_back_scan_png, trbgra_narc = custom_target('trbgra.narc', output: [ 'trbgra.narc', - 'trbgra.naix.h', + 'trbgra.naix', ], input: [ trainer_back_NCGR, @@ -278,10 +279,11 @@ trbgra_narc = custom_target('trbgra.narc', trainer_back_scan_NCGR, ], command: [ - narc_exe, 'create', - '--naix', - '--order', trbgra_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', trbgra_order, + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) @@ -356,11 +358,10 @@ trainer_encounter_NCLR = nclr_gen.process(trainer_encounter_pal, trainer_encounter_paste = copy_gen.process(trainer_encounter_copy, preserve_path_from: trainer_classes_root,) -field_encounteffect_order = files('field_encounteffect.order') field_encounteffect_narc = custom_target('field_encounteffect.narc', output: [ 'field_encounteffect.narc', - 'field_encounteffect.naix.h', + 'field_encounteffect.naix', ], input: [ trainer_encounter_mugshot_NCGR, @@ -375,10 +376,11 @@ field_encounteffect_narc = custom_target('field_encounteffect.narc', frontier_vs_anim_NANR, ], command: [ - narc_exe, 'create', - '--naix', - '--order', field_encounteffect_order, - '--output', '@OUTPUT0@', + nitroarc_exe, + '--create', + '--index', + '--files-from', files('field_encounteffect.order'), + '--file', '@OUTPUT0@', '@PRIVATE_DIR@', ], ) diff --git a/res/trainers/meson.build b/res/trainers/meson.build index 88bf3bf758..45a3a16fda 100644 --- a/res/trainers/meson.build +++ b/res/trainers/meson.build @@ -65,16 +65,15 @@ ball_capsules_bin = generator( ball_capsules_narc = custom_target('trainer_ball_capsules.narc', output: [ 'trainer_ball_capsules.narc', - 'trainer_ball_capsules.naix.h', - ], - input: [ - ball_capsules_bin, + 'trainer_ball_capsules.naix', ], + input: ball_capsules_bin, command: [ - narc_exe, 'create', - '--naix', - '--output', '@OUTPUT0@', - '@PRIVATE_DIR@' + nitroarc_exe, + '--create', + '--index', + '--file', '@OUTPUT0@', + '@PRIVATE_DIR@', ], depends: [ py_consts_generators ], ) diff --git a/src/applications/bag/main.c b/src/applications/bag/main.c index 3d1e6103b3..39d044fa6b 100644 --- a/src/applications/bag/main.c +++ b/src/applications/bag/main.c @@ -50,7 +50,7 @@ #include "unk_0208C098.h" #include "vram_transfer.h" -#include "res/graphics/bag/bag_graphics.naix.h" +#include "res/graphics/bag/bag_graphics.naix" #include "res/text/bank/bag.h" #define DIAL_CENTER_X (HW_LCD_WIDTH / 2) diff --git a/src/applications/bag/sprites.c b/src/applications/bag/sprites.c index 44c9c27a53..7dad33eb16 100644 --- a/src/applications/bag/sprites.c +++ b/src/applications/bag/sprites.c @@ -19,8 +19,8 @@ #include "type_icon.h" #include "vram_transfer.h" -#include "res/graphics/bag/bag_graphics.naix.h" -#include "res/graphics/shop_menu/shop_gra.naix.h" +#include "res/graphics/bag/bag_graphics.naix" +#include "res/graphics/shop_menu/shop_gra.naix" static void InitSpriteSystem(BagController *controller); static void LoadSpriteResources(BagController *controller); diff --git a/src/applications/bag/windows.c b/src/applications/bag/windows.c index 245eb48ee7..5fa999f832 100644 --- a/src/applications/bag/windows.c +++ b/src/applications/bag/windows.c @@ -28,7 +28,7 @@ #include "text.h" #include "trainer_info.h" -#include "res/graphics/bag/bag_graphics.naix.h" +#include "res/graphics/bag/bag_graphics.naix" #include "res/text/bank/bag.h" #define ITEM_LIST_WINDOW_WIDTH 17 diff --git a/src/applications/diploma.c b/src/applications/diploma.c index 711d1c70f1..fb86d7de8e 100644 --- a/src/applications/diploma.c +++ b/src/applications/diploma.c @@ -20,7 +20,7 @@ #include "text.h" #include "trainer_info.h" -#include "res/graphics/diploma/diploma.naix.h" +#include "res/graphics/diploma/diploma.naix" #include "res/text/bank/diploma.h" typedef struct Diploma { diff --git a/src/applications/naming_screen.c b/src/applications/naming_screen.c index 2bcdf38816..0a5cd532d7 100644 --- a/src/applications/naming_screen.c +++ b/src/applications/naming_screen.c @@ -48,7 +48,7 @@ #include "unk_0201567C.h" #include "vram_transfer.h" -#include "res/graphics/naming_screen/namein.naix.h" +#include "res/graphics/naming_screen/namein.naix" #include "res/text/bank/generic_names.h" #include "res/text/bank/naming_screen.h" diff --git a/src/applications/options_menu.c b/src/applications/options_menu.c index d042d00c16..a155b4531a 100644 --- a/src/applications/options_menu.c +++ b/src/applications/options_menu.c @@ -29,7 +29,7 @@ #include "unk_020393C8.h" #include "vram_transfer.h" -#include "res/graphics/options_menu/config_gra.naix.h" +#include "res/graphics/options_menu/config_gra.naix" #include "res/text/bank/options_menu.h" #define MENU_TITLE_BASE_TILE 10 diff --git a/src/applications/party_menu/form_change.c b/src/applications/party_menu/form_change.c index b5d42be07e..8bfcfeb364 100644 --- a/src/applications/party_menu/form_change.c +++ b/src/applications/party_menu/form_change.c @@ -25,7 +25,7 @@ #include "text.h" #include "unk_0202419C.h" -#include "res/graphics/party_menu/form_changes/form_change_effects.naix.h" +#include "res/graphics/party_menu/form_changes/form_change_effects.naix" #include "res/text/bank/party_menu.h" static void PartyMenuFormChange_Free(PartyMenuApplication *app); diff --git a/src/applications/party_menu/main.c b/src/applications/party_menu/main.c index d1f4efe24b..7fc0eb4037 100644 --- a/src/applications/party_menu/main.c +++ b/src/applications/party_menu/main.c @@ -64,7 +64,7 @@ #include "unk_0206B9D8.h" #include "vram_transfer.h" -#include "res/graphics/party_menu/party_menu_graphics.naix.h" +#include "res/graphics/party_menu/party_menu_graphics.naix" #include "res/text/bank/party_menu.h" FS_EXTERN_OVERLAY(party_menu_form_change); diff --git a/src/applications/poffin_case/cutscene.c b/src/applications/poffin_case/cutscene.c index b9559bbd20..bedd3c2b30 100644 --- a/src/applications/poffin_case/cutscene.c +++ b/src/applications/poffin_case/cutscene.c @@ -33,7 +33,7 @@ #include "unk_0208C098.h" #include "vram_transfer.h" -#include "res/graphics/poffin_case/feeding_cutscene/cutscene.naix.h" +#include "res/graphics/poffin_case/feeding_cutscene/cutscene.naix" #define MON_SPRITE_FAR_SIZE 0x1000 #define MON_SPRITE_FAR_X 128 diff --git a/src/applications/poffin_case/manager.c b/src/applications/poffin_case/manager.c index 9f55f91c2e..5f0d3de8cf 100644 --- a/src/applications/poffin_case/manager.c +++ b/src/applications/poffin_case/manager.c @@ -32,7 +32,7 @@ #include "unk_0208C098.h" #include "vram_transfer.h" -#include "res/graphics/poffin_case/poru_gra.naix.h" +#include "res/graphics/poffin_case/poru_gra.naix" #include "res/text/bank/poffin_case.h" typedef enum PoffinManagerState { diff --git a/src/applications/pokedex/crysub.c b/src/applications/pokedex/crysub.c index b53befdd12..800f1a1d24 100644 --- a/src/applications/pokedex/crysub.c +++ b/src/applications/pokedex/crysub.c @@ -33,7 +33,7 @@ #include "unk_02012744.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" /* diff --git a/src/applications/pokedex/footprint.c b/src/applications/pokedex/footprint.c index ec30a028c6..96ef42da20 100644 --- a/src/applications/pokedex/footprint.c +++ b/src/applications/pokedex/footprint.c @@ -1,6 +1,6 @@ #include "applications/pokedex/footprint.h" -#include "res/pokemon/pokefoot.naix.h" +#include "res/pokemon/pokefoot.naix" enum NarcID GetPokedexFootprintsNarcID(void) { diff --git a/src/applications/pokedex/formmain.c b/src/applications/pokedex/formmain.c index 781450ad81..8bc9cd96f8 100644 --- a/src/applications/pokedex/formmain.c +++ b/src/applications/pokedex/formmain.c @@ -29,7 +29,7 @@ #include "sprite_util.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" /* diff --git a/src/applications/pokedex/formsub.c b/src/applications/pokedex/formsub.c index 61bf18067b..ad91ca2615 100644 --- a/src/applications/pokedex/formsub.c +++ b/src/applications/pokedex/formsub.c @@ -31,7 +31,7 @@ #include "unk_02012744.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" /* diff --git a/src/applications/pokedex/infomain_foreign.c b/src/applications/pokedex/infomain_foreign.c index 4f64c7e9d6..ffa0d6a025 100644 --- a/src/applications/pokedex/infomain_foreign.c +++ b/src/applications/pokedex/infomain_foreign.c @@ -31,7 +31,7 @@ #include "text.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" #define POKEDEX_TYPE_ICON_BACKGROUND_BOX_CELL 0x11 diff --git a/src/applications/pokedex/ov21_021D5AEC.c b/src/applications/pokedex/ov21_021D5AEC.c index 2a63392666..084535aab6 100644 --- a/src/applications/pokedex/ov21_021D5AEC.c +++ b/src/applications/pokedex/ov21_021D5AEC.c @@ -32,7 +32,7 @@ #include "text.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021D76B0.c b/src/applications/pokedex/ov21_021D76B0.c index 8e341707a3..65352f7e19 100644 --- a/src/applications/pokedex/ov21_021D76B0.c +++ b/src/applications/pokedex/ov21_021D76B0.c @@ -33,7 +33,7 @@ #include "touch_screen_actions.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021D94BC.c b/src/applications/pokedex/ov21_021D94BC.c index 67b1537a87..9d2e1078de 100644 --- a/src/applications/pokedex/ov21_021D94BC.c +++ b/src/applications/pokedex/ov21_021D94BC.c @@ -31,7 +31,7 @@ #include "touch_screen_actions.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021DC9BC.c b/src/applications/pokedex/ov21_021DC9BC.c index acbd844ff5..47dc2d5e09 100644 --- a/src/applications/pokedex/ov21_021DC9BC.c +++ b/src/applications/pokedex/ov21_021DC9BC.c @@ -29,7 +29,7 @@ #include "sprite_util.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" #define TERMINALVALUE 0xffff diff --git a/src/applications/pokedex/ov21_021DDD2C.c b/src/applications/pokedex/ov21_021DDD2C.c index 288f523773..02550c21a7 100644 --- a/src/applications/pokedex/ov21_021DDD2C.c +++ b/src/applications/pokedex/ov21_021DDD2C.c @@ -29,7 +29,7 @@ #include "touch_screen_actions.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" typedef struct { PokedexScreenManager *unk_00; diff --git a/src/applications/pokedex/ov21_021DE668.c b/src/applications/pokedex/ov21_021DE668.c index 9570748ec6..fc26bf8cf9 100644 --- a/src/applications/pokedex/ov21_021DE668.c +++ b/src/applications/pokedex/ov21_021DE668.c @@ -35,7 +35,7 @@ #include "text.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021E1924.c b/src/applications/pokedex/ov21_021E1924.c index 20529ba4f5..4d14397cd3 100644 --- a/src/applications/pokedex/ov21_021E1924.c +++ b/src/applications/pokedex/ov21_021E1924.c @@ -36,7 +36,7 @@ #include "unk_02012744.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021E29DC.c b/src/applications/pokedex/ov21_021E29DC.c index d3e84ca220..f3748f7bfa 100644 --- a/src/applications/pokedex/ov21_021E29DC.c +++ b/src/applications/pokedex/ov21_021E29DC.c @@ -36,7 +36,7 @@ #include "touch_screen_actions.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021E3FFC.c b/src/applications/pokedex/ov21_021E3FFC.c index 7d178a57a3..723bbabdce 100644 --- a/src/applications/pokedex/ov21_021E3FFC.c +++ b/src/applications/pokedex/ov21_021E3FFC.c @@ -25,7 +25,7 @@ #include "sprite_transfer.h" #include "sprite_util.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" typedef struct { int *unk_00; diff --git a/src/applications/pokedex/ov21_021E68F4.c b/src/applications/pokedex/ov21_021E68F4.c index 8e0b3ce743..7db392f1c5 100644 --- a/src/applications/pokedex/ov21_021E68F4.c +++ b/src/applications/pokedex/ov21_021E68F4.c @@ -32,7 +32,7 @@ #include "unk_02012744.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021E737C.c b/src/applications/pokedex/ov21_021E737C.c index 571f2483a2..c044ff5305 100644 --- a/src/applications/pokedex/ov21_021E737C.c +++ b/src/applications/pokedex/ov21_021E737C.c @@ -34,7 +34,7 @@ #include "text.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/ov21_021E8D48.c b/src/applications/pokedex/ov21_021E8D48.c index c29daf9f07..8d39d4446d 100644 --- a/src/applications/pokedex/ov21_021E8D48.c +++ b/src/applications/pokedex/ov21_021E8D48.c @@ -32,7 +32,7 @@ #include "text.h" #include "vram_transfer.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/pokedex_graphics.c b/src/applications/pokedex/pokedex_graphics.c index 01c6ae596f..f1c1690c27 100644 --- a/src/applications/pokedex/pokedex_graphics.c +++ b/src/applications/pokedex/pokedex_graphics.c @@ -11,7 +11,7 @@ #include "sys_task.h" #include "unk_02012744.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" static void InitBackgrounds(BgConfig *bgConfig, enum HeapID heapID); static void FreeBackgrounds(BgConfig *bgConfig); diff --git a/src/applications/pokedex/pokedex_height_check.c b/src/applications/pokedex/pokedex_height_check.c index 1c233463ac..d0c12968cc 100644 --- a/src/applications/pokedex/pokedex_height_check.c +++ b/src/applications/pokedex/pokedex_height_check.c @@ -30,7 +30,7 @@ #include "string_gf.h" #include "text.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" typedef struct { diff --git a/src/applications/pokedex/pokedex_search.c b/src/applications/pokedex/pokedex_search.c index 33095ccd6e..489dad1727 100644 --- a/src/applications/pokedex/pokedex_search.c +++ b/src/applications/pokedex/pokedex_search.c @@ -29,7 +29,7 @@ #include "string_gf.h" #include "text.h" -#include "res/graphics/pokedex/zukan.naix.h" +#include "res/graphics/pokedex/zukan.naix" #include "res/text/bank/pokedex.h" #define EXITSEARCH (1 << 1) diff --git a/src/applications/pokemon_summary_screen/main.c b/src/applications/pokemon_summary_screen/main.c index ffb79a604a..a719dd3cca 100644 --- a/src/applications/pokemon_summary_screen/main.c +++ b/src/applications/pokemon_summary_screen/main.c @@ -57,7 +57,7 @@ #include "vram_transfer.h" #include "constdata/const_020F410C.h" -#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix.h" +#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix" #include "res/text/bank/pokemon_summary_screen.h" enum SummaryState { diff --git a/src/applications/pokemon_summary_screen/sprites.c b/src/applications/pokemon_summary_screen/sprites.c index b291f7eb30..c0750e5d39 100644 --- a/src/applications/pokemon_summary_screen/sprites.c +++ b/src/applications/pokemon_summary_screen/sprites.c @@ -21,7 +21,7 @@ #include "type_icon.h" #include "vram_transfer.h" -#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix.h" +#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix" static void SetTypeIcon(PokemonSummaryScreen *summaryScreen, u8 spriteIndex, u8 param2, u8 type); static void SetMonAndTypeIcons(PokemonSummaryScreen *summaryScreen); diff --git a/src/applications/poketch/alarm_clock/graphics.c b/src/applications/poketch/alarm_clock/graphics.c index ef92976554..28a617bb15 100644 --- a/src/applications/poketch/alarm_clock/graphics.c +++ b/src/applications/poketch/alarm_clock/graphics.c @@ -13,7 +13,7 @@ #include "sound_playback.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define SPRITE_ALARM_SET_BUTTON 0 #define SPRITE_EAR_LEFT 1 diff --git a/src/applications/poketch/analog_watch/graphics.c b/src/applications/poketch/analog_watch/graphics.c index 9fa252cb14..ff6cac5df9 100644 --- a/src/applications/poketch/analog_watch/graphics.c +++ b/src/applications/poketch/analog_watch/graphics.c @@ -12,7 +12,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *graphics); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/backlight_toggle/graphics.c b/src/applications/poketch/backlight_toggle/graphics.c index fc2cb79465..1f2822f579 100644 --- a/src/applications/poketch/backlight_toggle/graphics.c +++ b/src/applications/poketch/backlight_toggle/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void SetupSprites(BacklightToggleGraphics *graphics, const BacklightData *backlight); static void UnloadSprites(BacklightToggleGraphics *graphics); diff --git a/src/applications/poketch/berry_searcher/graphics.c b/src/applications/poketch/berry_searcher/graphics.c index ebf02055d9..0164678cc2 100644 --- a/src/applications/poketch/berry_searcher/graphics.c +++ b/src/applications/poketch/berry_searcher/graphics.c @@ -17,7 +17,7 @@ #include "sys_task_manager.h" #include "text.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define ANIM_INDEX_CURSOR 0 #define ANIM_INDEX_BERRY 7 diff --git a/src/applications/poketch/calculator/graphics.c b/src/applications/poketch/calculator/graphics.c index 14c613895a..10d0cbdaa7 100644 --- a/src/applications/poketch/calculator/graphics.c +++ b/src/applications/poketch/calculator/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define CALCULATOR_NCGR_WIDTH_TILES 40 diff --git a/src/applications/poketch/calendar/graphics.c b/src/applications/poketch/calendar/graphics.c index 6b3e82fcfd..9ea8a0ccb7 100644 --- a/src/applications/poketch/calendar/graphics.c +++ b/src/applications/poketch/calendar/graphics.c @@ -11,7 +11,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define MARKED_CELL_TILE_IDX 143 #define UNMARKED_CELL_TILE_IDX 131 diff --git a/src/applications/poketch/coin_toss/graphics.c b/src/applications/poketch/coin_toss/graphics.c index d438d47650..8826b3f80a 100644 --- a/src/applications/poketch/coin_toss/graphics.c +++ b/src/applications/poketch/coin_toss/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define ANIM_INDEX_SPINNING 0 #define ANIM_INDEX_HEADS 1 diff --git a/src/applications/poketch/color_changer/graphics.c b/src/applications/poketch/color_changer/graphics.c index b054e76350..c2e9ffd3d0 100644 --- a/src/applications/poketch/color_changer/graphics.c +++ b/src/applications/poketch/color_changer/graphics.c @@ -15,7 +15,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void SetupSprites(ColorChangerGraphics *graphics, const ColorChangerData *colorData); static void UnloadSprites(ColorChangerGraphics *graphics); diff --git a/src/applications/poketch/counter/graphics.c b/src/applications/poketch/counter/graphics.c index 11afe9c6c6..24373f2d00 100644 --- a/src/applications/poketch/counter/graphics.c +++ b/src/applications/poketch/counter/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void SetupSprites(CounterGraphics *graphics, const CounterData *counterData); static void UnloadSprites(CounterGraphics *graphics); diff --git a/src/applications/poketch/daycare_checker/graphics.c b/src/applications/poketch/daycare_checker/graphics.c index 06f92affc5..8cbde9437c 100644 --- a/src/applications/poketch/daycare_checker/graphics.c +++ b/src/applications/poketch/daycare_checker/graphics.c @@ -18,7 +18,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void SetupSprites(DaycareCheckerGraphics *graphics, const DaycareStatus *daycareStatus); static void UnloadSprites(DaycareCheckerGraphics *graphics); diff --git a/src/applications/poketch/digital_watch/graphics.c b/src/applications/poketch/digital_watch/graphics.c index a3e2e7e77a..a4dc659650 100644 --- a/src/applications/poketch/digital_watch/graphics.c +++ b/src/applications/poketch/digital_watch/graphics.c @@ -10,7 +10,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void CopyDigitTilemap(const u16 *rawScreenData, u16 *dst); diff --git a/src/applications/poketch/dowsing_machine/graphics.c b/src/applications/poketch/dowsing_machine/graphics.c index 3d244ee240..8e4a9f86c9 100644 --- a/src/applications/poketch/dowsing_machine/graphics.c +++ b/src/applications/poketch/dowsing_machine/graphics.c @@ -11,7 +11,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/friendship_checker/graphics.c b/src/applications/poketch/friendship_checker/graphics.c index e818748706..c1b0b64eff 100644 --- a/src/applications/poketch/friendship_checker/graphics.c +++ b/src/applications/poketch/friendship_checker/graphics.c @@ -20,7 +20,7 @@ #include "sys_task_manager.h" #include "system.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define TIME_STEPS_PER_FRAME 16 diff --git a/src/applications/poketch/kitchen_timer/graphics.c b/src/applications/poketch/kitchen_timer/graphics.c index db1b665ad9..01df51f18a 100644 --- a/src/applications/poketch/kitchen_timer/graphics.c +++ b/src/applications/poketch/kitchen_timer/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define ANIM_HAND_RIGHT_UP 0 #define ANIM_HAND_RIGHT_DOWN 1 diff --git a/src/applications/poketch/link_searcher/graphics.c b/src/applications/poketch/link_searcher/graphics.c index a74c7fa052..9be42f5740 100644 --- a/src/applications/poketch/link_searcher/graphics.c +++ b/src/applications/poketch/link_searcher/graphics.c @@ -18,7 +18,7 @@ #include "sys_task_manager.h" #include "text.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #include "res/text/bank/poketch_link_searcher.h" #define SPRITE_DS 0 diff --git a/src/applications/poketch/marking_map/graphics.c b/src/applications/poketch/marking_map/graphics.c index 1a0558589f..9710a51526 100644 --- a/src/applications/poketch/marking_map/graphics.c +++ b/src/applications/poketch/marking_map/graphics.c @@ -15,7 +15,7 @@ #include "heap.h" #include "sys_task.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define ANIMATION_INDEX_CURSOR 0 #define ANIMATION_INDEX_MARKER 1 diff --git a/src/applications/poketch/matchup_checker/graphics.c b/src/applications/poketch/matchup_checker/graphics.c index a8079517cb..cf55bcbd0b 100644 --- a/src/applications/poketch/matchup_checker/graphics.c +++ b/src/applications/poketch/matchup_checker/graphics.c @@ -16,7 +16,7 @@ #include "pokemon_icon.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define ANIM_COMMAND_END -1 #define ANIM_COMMAND_MOVE_FORWARD -2 diff --git a/src/applications/poketch/memo_pad/graphics.c b/src/applications/poketch/memo_pad/graphics.c index 4bb3580916..23e60df9d4 100644 --- a/src/applications/poketch/memo_pad/graphics.c +++ b/src/applications/poketch/memo_pad/graphics.c @@ -16,7 +16,7 @@ #include "poketch_memory.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define WINDOW_WIDTH_TILES 20 #define WINDOW_HEIGHT_TILES 19 diff --git a/src/applications/poketch/move_tester/graphics.c b/src/applications/poketch/move_tester/graphics.c index 1e400e6191..76492ffd6e 100644 --- a/src/applications/poketch/move_tester/graphics.c +++ b/src/applications/poketch/move_tester/graphics.c @@ -24,7 +24,7 @@ #include "sys_task_manager.h" #include "text.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #include "res/text/bank/poketch_move_tester.h" static const PoketchAnimation_AnimationData sPoketchMoveTester_AnimDataButtons[] = { diff --git a/src/applications/poketch/party_status/graphics.c b/src/applications/poketch/party_status/graphics.c index fb9e18c025..7f37813645 100644 --- a/src/applications/poketch/party_status/graphics.c +++ b/src/applications/poketch/party_status/graphics.c @@ -19,7 +19,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define POKE_ICON_TILE_COUNT 16 #define POKE_ICON_SIZE_BYTES (POKE_ICON_TILE_COUNT * TILE_SIZE_4BPP) diff --git a/src/applications/poketch/pedometer/graphics.c b/src/applications/poketch/pedometer/graphics.c index 1ac6709da5..6154b3dbd5 100644 --- a/src/applications/poketch/pedometer/graphics.c +++ b/src/applications/poketch/pedometer/graphics.c @@ -14,7 +14,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void SetupSprites(PedometerGraphics *graphics, const PedometerData *pedometerData); static void UnloadSprites(PedometerGraphics *graphics); diff --git a/src/applications/poketch/pokemon_history/graphics.c b/src/applications/poketch/pokemon_history/graphics.c index cda4345c46..cd14028c33 100644 --- a/src/applications/poketch/pokemon_history/graphics.c +++ b/src/applications/poketch/pokemon_history/graphics.c @@ -15,7 +15,7 @@ #include "sys_task_manager.h" #include "text.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define MON_ANIM_DATA(r, c) \ { \ diff --git a/src/applications/poketch/poketch_graphics.c b/src/applications/poketch/poketch_graphics.c index e917e1e4be..e1f87386eb 100644 --- a/src/applications/poketch/poketch_graphics.c +++ b/src/applications/poketch/poketch_graphics.c @@ -17,7 +17,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" /* The poketch palette file contains 16 pallets of 16 colors each. diff --git a/src/applications/poketch/roulette/graphics.c b/src/applications/poketch/roulette/graphics.c index 6cab26fca7..e0f0c9b126 100644 --- a/src/applications/poketch/roulette/graphics.c +++ b/src/applications/poketch/roulette/graphics.c @@ -16,7 +16,7 @@ #include "poketch_memory.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define WINDOW_WIDTH_TILES 20 #define WINDOW_HEIGHT_TILES 19 diff --git a/src/applications/poketch/stopwatch/graphics.c b/src/applications/poketch/stopwatch/graphics.c index 4fb801d949..0ef0072b8d 100644 --- a/src/applications/poketch/stopwatch/graphics.c +++ b/src/applications/poketch/stopwatch/graphics.c @@ -15,7 +15,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" #define BUTTON_WIDTH_TILES 5 #define BUTTON_HEIGHT_TILES 11 diff --git a/src/applications/poketch/trainer_counter/graphics.c b/src/applications/poketch/trainer_counter/graphics.c index 9e724eea56..d89a5b1461 100644 --- a/src/applications/poketch/trainer_counter/graphics.c +++ b/src/applications/poketch/trainer_counter/graphics.c @@ -16,7 +16,7 @@ #include "pokemon_icon.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/unavailable/graphics.c b/src/applications/poketch/unavailable/graphics.c index 0b9cfc3d54..0577c77043 100644 --- a/src/applications/poketch/unavailable/graphics.c +++ b/src/applications/poketch/unavailable/graphics.c @@ -7,7 +7,7 @@ #include "heap.h" #include "narc.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" void PoketchUnavailableScreen_Init(BgConfig *bgConfig) { diff --git a/src/applications/poketch/unused/1/graphics.c b/src/applications/poketch/unused/1/graphics.c index 385a12d4a2..faeddf9d9a 100644 --- a/src/applications/poketch/unused/1/graphics.c +++ b/src/applications/poketch/unused/1/graphics.c @@ -10,7 +10,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/unused/2/graphics.c b/src/applications/poketch/unused/2/graphics.c index 133741b775..0abe0e0350 100644 --- a/src/applications/poketch/unused/2/graphics.c +++ b/src/applications/poketch/unused/2/graphics.c @@ -10,7 +10,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/unused/3/graphics.c b/src/applications/poketch/unused/3/graphics.c index cf47836634..e097a1f3ab 100644 --- a/src/applications/poketch/unused/3/graphics.c +++ b/src/applications/poketch/unused/3/graphics.c @@ -10,7 +10,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/poketch/unused/4/graphics.c b/src/applications/poketch/unused/4/graphics.c index 6de9726315..489cc5416b 100644 --- a/src/applications/poketch/unused/4/graphics.c +++ b/src/applications/poketch/unused/4/graphics.c @@ -10,7 +10,7 @@ #include "heap.h" #include "sys_task_manager.h" -#include "res/graphics/poketch/poketch.naix.h" +#include "res/graphics/poketch/poketch.naix" static void EndTask(PoketchTaskManager *taskMan); static void Task_DrawBackground(SysTask *task, void *taskMan); diff --git a/src/applications/title_screen.c b/src/applications/title_screen.c index 9b49d99693..50fbbcad59 100644 --- a/src/applications/title_screen.c +++ b/src/applications/title_screen.c @@ -33,7 +33,7 @@ #include "text.h" #include "unk_0202419C.h" -#include "res/graphics/title_screen/titledemo.naix.h" +#include "res/graphics/title_screen/titledemo.naix" FS_EXTERN_OVERLAY(game_opening); FS_EXTERN_OVERLAY(main_menu); diff --git a/src/applications/town_map/main.c b/src/applications/town_map/main.c index e3a299bbea..c6b97be397 100644 --- a/src/applications/town_map/main.c +++ b/src/applications/town_map/main.c @@ -24,7 +24,7 @@ #include "touch_pad.h" #include "unk_0208C098.h" -#include "res/graphics/town_map/town_map_graphics.naix.h" +#include "res/graphics/town_map/town_map_graphics.naix" enum TownMapAppState { TOWN_MAP_APP_STATE_INIT_RESOURCES, diff --git a/src/battle/battle_controller_player.c b/src/battle/battle_controller_player.c index dcfae2ab7d..f746c7ba00 100644 --- a/src/battle/battle_controller_player.c +++ b/src/battle/battle_controller_player.c @@ -44,7 +44,7 @@ #include "sound_playback.h" #include "trainer_info.h" -#include "res/battle/scripts/sub_seq.naix.h" +#include "res/battle/scripts/sub_seq.naix" enum BattleControllerState { STATE_PROCESSING = 0, diff --git a/src/battle/battle_lib.c b/src/battle/battle_lib.c index a5e6a60a75..26c45fc3c2 100644 --- a/src/battle/battle_lib.c +++ b/src/battle/battle_lib.c @@ -44,7 +44,7 @@ #include "unk_020366A0.h" #include "unk_0208C098.h" -#include "res/battle/scripts/sub_seq.naix.h" +#include "res/battle/scripts/sub_seq.naix" #include "res/text/bank/battle_strings.h" #define TRMSG_ACTIVE_BATTLER_HALF_HP_FLAG 2 diff --git a/src/battle/battle_script.c b/src/battle/battle_script.c index 78edd0e957..bb74aa30e2 100644 --- a/src/battle/battle_script.c +++ b/src/battle/battle_script.c @@ -75,7 +75,7 @@ #include "unk_0201567C.h" #include "unk_0208C098.h" -#include "res/battle/scripts/sub_seq.naix.h" +#include "res/battle/scripts/sub_seq.naix" #include "res/text/bank/battle_strings.h" typedef BOOL (*BtlCmd)(BattleSystem *, BattleContext *); diff --git a/src/cutscenes/boat_cutscene/boat_cutscene.c b/src/cutscenes/boat_cutscene/boat_cutscene.c index a8c8e85420..9371439cbb 100644 --- a/src/cutscenes/boat_cutscene/boat_cutscene.c +++ b/src/cutscenes/boat_cutscene/boat_cutscene.c @@ -24,7 +24,7 @@ #include "unk_0203D1B8.h" #include "unk_020553DC.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" #define BOAT_CUTSCENE_STATE_START_WITHOUT_BRIDGE 0 #define BOAT_CUTSCENE_STATE_START_WITH_BRIDGE 1 diff --git a/src/evolution.c b/src/evolution.c index af182190c2..a01ea9ed69 100644 --- a/src/evolution.c +++ b/src/evolution.c @@ -55,7 +55,7 @@ #include "vram_transfer.h" #include "constdata/const_020F410C.h" -#include "res/graphics/diploma/diploma.naix.h" +#include "res/graphics/diploma/diploma.naix" #include "res/text/bank/battle_strings.h" static void SysTask_Evolution(SysTask *task, void *data); diff --git a/src/font.c b/src/font.c index ebb6e31b2d..6c1825cf91 100644 --- a/src/font.c +++ b/src/font.c @@ -15,7 +15,7 @@ #include "string_gf.h" #include "text.h" -#include "res/fonts/pl_font.naix.h" +#include "res/fonts/pl_font.naix" typedef struct { TextGlyph curGlyph; diff --git a/src/font_special_chars.c b/src/font_special_chars.c index 9f8e02a8bb..56714c836e 100644 --- a/src/font_special_chars.c +++ b/src/font_special_chars.c @@ -9,7 +9,7 @@ #include "graphics.h" #include "heap.h" -#include "res/fonts/pl_font.naix.h" +#include "res/fonts/pl_font.naix" #define BG_COLOR_F (0) #define FG_COLOR_F (1 << 0) diff --git a/src/item.c b/src/item.c index c1ab469561..8c8bd7be1f 100644 --- a/src/item.c +++ b/src/item.c @@ -13,7 +13,7 @@ #include "narc.h" #include "string_gf.h" -#include "res/graphics/item_icons/item_icon.naix.h" +#include "res/graphics/item_icons/item_icon.naix" typedef struct ItemArchiveIDs { u16 dataID; // Member file index in pl_item_data.narc; TODO: Use NAIX generated from pl_item_data diff --git a/src/main_menu/gba_migrator.c b/src/main_menu/gba_migrator.c index 2fb3752014..4828f310d3 100644 --- a/src/main_menu/gba_migrator.c +++ b/src/main_menu/gba_migrator.c @@ -63,7 +63,7 @@ #include "unk_0209A74C.h" #include "vram_transfer.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" #include "res/text/bank/migrate_from_gba.h" FS_EXTERN_OVERLAY(game_opening); diff --git a/src/main_menu/main_menu.c b/src/main_menu/main_menu.c index b087480811..efd0f0dcc5 100644 --- a/src/main_menu/main_menu.c +++ b/src/main_menu/main_menu.c @@ -49,7 +49,7 @@ #include "unk_0209A74C.h" #include "vram_transfer.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" #include "res/text/bank/main_menu_alerts.h" #include "res/text/bank/main_menu_options.h" #include "res/text/bank/unk_0695.h" diff --git a/src/main_menu/main_menu_util.c b/src/main_menu/main_menu_util.c index 82dc2ce0f1..af800a2467 100644 --- a/src/main_menu/main_menu_util.c +++ b/src/main_menu/main_menu_util.c @@ -45,7 +45,7 @@ #include "versions.h" #include "vram_transfer.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" #define WONDER_CARD_ENCRYPTION_MAGIC 0xD679 diff --git a/src/main_menu/mystery_gift_app.c b/src/main_menu/mystery_gift_app.c index 119e85ae0a..c8d7513e9e 100644 --- a/src/main_menu/mystery_gift_app.c +++ b/src/main_menu/mystery_gift_app.c @@ -59,7 +59,7 @@ #include "unk_020366A0.h" #include "unk_020393C8.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" #include "res/text/bank/mystery_gift_menu.h" #include "res/text/bank/unk_0695.h" diff --git a/src/main_menu/ov97_0222C174.c b/src/main_menu/ov97_0222C174.c index 08496fa19a..f0916ac1a1 100644 --- a/src/main_menu/ov97_0222C174.c +++ b/src/main_menu/ov97_0222C174.c @@ -39,7 +39,7 @@ #include "unk_02033200.h" #include "unk_020393C8.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" FS_EXTERN_OVERLAY(game_opening); diff --git a/src/main_menu/wonder_cards_app.c b/src/main_menu/wonder_cards_app.c index 3d2c4ff850..9a265e16a4 100644 --- a/src/main_menu/wonder_cards_app.c +++ b/src/main_menu/wonder_cards_app.c @@ -51,7 +51,7 @@ #include "unk_020366A0.h" #include "unk_020393C8.h" -#include "res/graphics/main_menu/main_menu_graphics.naix.h" +#include "res/graphics/main_menu/main_menu_graphics.naix" #include "res/text/bank/mystery_gift_menu.h" FS_EXTERN_OVERLAY(main_menu); diff --git a/src/overlay005/honey_tree.c b/src/overlay005/honey_tree.c index 945f9594d4..4412b103c8 100644 --- a/src/overlay005/honey_tree.c +++ b/src/overlay005/honey_tree.c @@ -21,7 +21,7 @@ #include "terrain_collision_manager.h" #include "trainer_info.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" #define TREE_GROUP_NO_ENCOUNTER 0 #define TREE_GROUP_A 1 diff --git a/src/overlay005/ov5_021D431C.c b/src/overlay005/ov5_021D431C.c index 159143a9c9..7d38afbcf9 100644 --- a/src/overlay005/ov5_021D431C.c +++ b/src/overlay005/ov5_021D431C.c @@ -24,7 +24,7 @@ #include "unk_02056B30.h" #include "unk_020655F4.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" typedef struct UnkStruct_ov5_021D432C_t { int unk_00; diff --git a/src/overlay006/elevator_animation.c b/src/overlay006/elevator_animation.c index 98d5401b3d..4d1f8bced9 100644 --- a/src/overlay006/elevator_animation.c +++ b/src/overlay006/elevator_animation.c @@ -15,7 +15,7 @@ #include "sound_playback.h" #include "terrain_collision_manager.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" #define ELEVATOR_ANIMATION_TAG 0x1 diff --git a/src/overlay006/healing_machine_animation/hall_of_fame.c b/src/overlay006/healing_machine_animation/hall_of_fame.c index b4ac9140e5..3d119be622 100644 --- a/src/overlay006/healing_machine_animation/hall_of_fame.c +++ b/src/overlay006/healing_machine_animation/hall_of_fame.c @@ -15,7 +15,7 @@ #include "party.h" #include "terrain_collision_manager.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" typedef struct HallOfFameHealingAnimation { VecFx32 position; diff --git a/src/overlay006/healing_machine_animation/pokecenter.c b/src/overlay006/healing_machine_animation/pokecenter.c index f81672a103..f9394228c8 100644 --- a/src/overlay006/healing_machine_animation/pokecenter.c +++ b/src/overlay006/healing_machine_animation/pokecenter.c @@ -16,7 +16,7 @@ #include "sound_playback.h" #include "terrain_collision_manager.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" typedef struct PokecenterHealingAnimation { VecFx32 position; diff --git a/src/overlay006/ov6_02242AF0.c b/src/overlay006/ov6_02242AF0.c index 192acca790..5402a224b2 100644 --- a/src/overlay006/ov6_02242AF0.c +++ b/src/overlay006/ov6_02242AF0.c @@ -22,7 +22,7 @@ #include "sound_playback.h" #include "unk_020655F4.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" typedef struct UnkStruct_ov6_02242B58_t UnkStruct_ov6_02242B58; diff --git a/src/overlay006/pc_animation.c b/src/overlay006/pc_animation.c index 16db3a103e..3ba4f16f48 100644 --- a/src/overlay006/pc_animation.c +++ b/src/overlay006/pc_animation.c @@ -10,7 +10,7 @@ #include "terrain_collision_manager.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" void FieldSystem_LoadPCAnimation(FieldSystem *fieldSystem, const u8 tag) { diff --git a/src/overlay007/accessory_shop.c b/src/overlay007/accessory_shop.c index 6942fe9d32..e5791e3117 100644 --- a/src/overlay007/accessory_shop.c +++ b/src/overlay007/accessory_shop.c @@ -26,7 +26,7 @@ #include "text.h" #include "unk_020298BC.h" -#include "res/graphics/shop_menu/shop_gra.naix.h" +#include "res/graphics/shop_menu/shop_gra.naix" #include "res/text/bank/flower_shop.h" static const AccessoryShopItem sAccessoryShop_ItemLists[ACCESSORY_SHOP_ITEM_LIST_COUNT] = { diff --git a/src/overlay007/shop_menu.c b/src/overlay007/shop_menu.c index bb6e797335..3c4c91870f 100644 --- a/src/overlay007/shop_menu.c +++ b/src/overlay007/shop_menu.c @@ -61,7 +61,7 @@ #include "unk_02097B18.h" #include "vars_flags.h" -#include "res/graphics/shop_menu/shop_gra.naix.h" +#include "res/graphics/shop_menu/shop_gra.naix" #include "res/text/bank/location_names.h" #include "res/text/bank/underground_goods.h" #include "res/text/bank/unk_0543.h" diff --git a/src/overlay008/ov8_02249960.c b/src/overlay008/ov8_02249960.c index 280efdefd3..437768977d 100644 --- a/src/overlay008/ov8_02249960.c +++ b/src/overlay008/ov8_02249960.c @@ -65,7 +65,7 @@ #include "unk_02067A84.h" #include "vars_flags.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" #include "res/text/bank/eterna_city_gym.h" typedef struct { diff --git a/src/overlay104/ov104_0222EA90.c b/src/overlay104/ov104_0222EA90.c index 778711d68a..e8c501f37d 100644 --- a/src/overlay104/ov104_0222EA90.c +++ b/src/overlay104/ov104_0222EA90.c @@ -14,7 +14,7 @@ #include "heap.h" #include "narc_frontier_bg.h" -#include "res/field/frontier_scripts/fr_script.naix.h" +#include "res/field/frontier_scripts/fr_script.naix" typedef void (*UnkFuncPtr_ov104_0223F394)(UnkStruct_ov104_0223C4CC *, void **); diff --git a/src/platform_lift.c b/src/platform_lift.c index 17f5f10ede..83756ff6b3 100644 --- a/src/platform_lift.c +++ b/src/platform_lift.c @@ -22,7 +22,7 @@ #include "sound_playback.h" #include "terrain_collision_manager.h" -#include "res/field/props/models/prop_models.naix.h" +#include "res/field/props/models/prop_models.naix" #define PLATFORM_LIFT_SIZE_X 3 #define PLATFORM_LIFT_SIZE_Y 2 diff --git a/src/pokemon_icon.c b/src/pokemon_icon.c index 9c73e05076..435b025343 100644 --- a/src/pokemon_icon.c +++ b/src/pokemon_icon.c @@ -8,7 +8,7 @@ #include "pokemon.h" -#include "res/pokemon/pl_poke_icon.naix.h" +#include "res/pokemon/pl_poke_icon.naix" #include "res/pokemon/species_icon_palettes.h" static inline u32 IconTilesIndex(u32 icon) diff --git a/src/pokemon_sprite.c b/src/pokemon_sprite.c index 19989efc0d..a08da15392 100644 --- a/src/pokemon_sprite.c +++ b/src/pokemon_sprite.c @@ -11,7 +11,7 @@ #include "palette.h" #include "pokemon_sprite.h" -#include "res/pokemon/pl_otherpoke.naix.h" +#include "res/pokemon/pl_otherpoke.naix" #define MAX_SPINDA_SPOTS 4 #define SPINDA_SPOT_COORDS_END 0xFF diff --git a/src/render_window.c b/src/render_window.c index 980eb5b4ea..5d40bcc39a 100644 --- a/src/render_window.c +++ b/src/render_window.c @@ -26,8 +26,8 @@ #include "sys_task_manager.h" #include "unk_0200679C.h" -#include "res/graphics/signposts/field_board.naix.h" -#include "res/graphics/windows/pl_winframe.naix.h" +#include "res/graphics/signposts/field_board.naix" +#include "res/graphics/windows/pl_winframe.naix" #define SIGNPOST_BORDER_LEFT_SIZE 1 #define SIGNPOST_BORDER_RIGHT_SIZE 2 diff --git a/src/ribbon.c b/src/ribbon.c index 44ef7ac76f..494c0a0116 100644 --- a/src/ribbon.c +++ b/src/ribbon.c @@ -5,7 +5,7 @@ #include "constants/pokemon.h" -#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix.h" +#include "res/graphics/pokemon_summary_screen/pl_pst_gra.naix" #include "res/text/bank/ribbon_names.h" typedef struct { diff --git a/src/script_manager.c b/src/script_manager.c index c85d8f08de..ca950a0155 100644 --- a/src/script_manager.c +++ b/src/script_manager.c @@ -26,7 +26,7 @@ #include "constdata/const_020EAB80.h" #include "constdata/const_020EAC58.h" -#include "res/field/scripts/scr_seq.naix.h" +#include "res/field/scripts/scr_seq.naix" // clang-format off #define SCRIPT_RANGE_TABLE(Entry) \ diff --git a/src/scroll_prompts.c b/src/scroll_prompts.c index af441f4fa3..dbe0a9bcb0 100644 --- a/src/scroll_prompts.c +++ b/src/scroll_prompts.c @@ -10,7 +10,7 @@ #include "sprite.h" #include "sprite_system.h" -#include "res/graphics/scroll_prompts/fld_comact.naix.h" +#include "res/graphics/scroll_prompts/fld_comact.naix" static const SpriteTemplate sArrowSpriteTemplates[] = { { diff --git a/src/start_menu.c b/src/start_menu.c index 3817002ef2..39ab617082 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -92,7 +92,7 @@ #include "vars_flags.h" #include "constdata/const_020EA02C.h" -#include "res/graphics/start_menu/start_menu.naix.h" +#include "res/graphics/start_menu/start_menu.naix" #include "res/text/bank/start_menu.h" typedef enum StartMenuPos { diff --git a/src/text.c b/src/text.c index 66ccac82f4..0d8040c092 100644 --- a/src/text.c +++ b/src/text.c @@ -15,7 +15,7 @@ #include "sys_task.h" #include "sys_task_manager.h" -#include "res/fonts/pl_font.naix.h" +#include "res/fonts/pl_font.naix" static enum RenderResult TextPrinter_Render(TextPrinter *printer); static u8 Text_CreatePrinterTask(SysTaskFunc taskFunc, TextPrinter *printer, u32 priority); diff --git a/src/underground/manager.c b/src/underground/manager.c index 0476e9af19..7770faf0b8 100644 --- a/src/underground/manager.c +++ b/src/underground/manager.c @@ -48,7 +48,7 @@ #include "unk_020366A0.h" #include "vars_flags.h" -#include "res/graphics/trap_effects/trap_effects.naix.h" +#include "res/graphics/trap_effects/trap_effects.naix" #include "res/text/bank/underground_common.h" #define MAX_STORED_MENU_POSITIONS 20 diff --git a/src/underground/menus.c b/src/underground/menus.c index 3ab5eaf3b9..5a3244f0e6 100644 --- a/src/underground/menus.c +++ b/src/underground/menus.c @@ -49,7 +49,7 @@ #include "trainer_info.h" #include "underground.h" -#include "res/graphics/start_menu/start_menu.naix.h" +#include "res/graphics/start_menu/start_menu.naix" #include "res/text/bank/underground_capture_flag.h" #include "res/text/bank/underground_common.h" #include "res/text/bank/underground_goods.h" diff --git a/src/underground/mining.c b/src/underground/mining.c index f223f8e408..96fdcecbcf 100644 --- a/src/underground/mining.c +++ b/src/underground/mining.c @@ -66,10 +66,10 @@ #include "vars_flags.h" #include "vram_transfer.h" -#include "res/graphics/mining/animations/animations.naix.h" -#include "res/graphics/mining/interface/interface.naix.h" -#include "res/graphics/mining/objects/objects.naix.h" -#include "res/graphics/trap_effects/trap_effects.naix.h" +#include "res/graphics/mining/animations/animations.naix" +#include "res/graphics/mining/interface/interface.naix" +#include "res/graphics/mining/objects/objects.naix" +#include "res/graphics/trap_effects/trap_effects.naix" #include "res/text/bank/underground_common.h" #define MAX_BURIED_OBJECTS 8 diff --git a/src/underground/secret_bases.c b/src/underground/secret_bases.c index 5d16501adb..8dc5cd1dde 100644 --- a/src/underground/secret_bases.c +++ b/src/underground/secret_bases.c @@ -64,8 +64,8 @@ #include "unk_020655F4.h" #include "vars_flags.h" -#include "res/field/props/models/prop_models.naix.h" -#include "res/graphics/trap_effects/trap_effects.naix.h" +#include "res/field/props/models/prop_models.naix" +#include "res/graphics/trap_effects/trap_effects.naix" #include "res/text/bank/underground_capture_flag.h" #include "res/text/bank/underground_common.h" diff --git a/src/underground/top_screen.c b/src/underground/top_screen.c index 60d62cb6a3..410fec0e93 100644 --- a/src/underground/top_screen.c +++ b/src/underground/top_screen.c @@ -31,8 +31,8 @@ #include "text.h" #include "unk_0200679C.h" -#include "res/graphics/trap_effects/trap_effects.naix.h" -#include "res/graphics/underground_top_screen/underground_top_screen.naix.h" +#include "res/graphics/trap_effects/trap_effects.naix" +#include "res/graphics/underground_top_screen/underground_top_screen.naix" #define MAX_QUEUE_SIZE 32 diff --git a/src/underground/traps.c b/src/underground/traps.c index 76dea7a115..05f80bf48c 100644 --- a/src/underground/traps.c +++ b/src/underground/traps.c @@ -57,7 +57,7 @@ #include "unk_020366A0.h" #include "vars_flags.h" -#include "res/graphics/trap_effects/trap_effects.naix.h" +#include "res/graphics/trap_effects/trap_effects.naix" #include "res/text/bank/underground_common.h" #define MAX_BUBBLES 20 diff --git a/subprojects/narc.wrap b/subprojects/narc.wrap deleted file mode 100644 index 6607a6e084..0000000000 --- a/subprojects/narc.wrap +++ /dev/null @@ -1,8 +0,0 @@ -[wrap-git] -url = https://github.com/lhearachel/narc.git -revision = v0.4.0 -depth = 1 - -[provide] -program_names = narc -dependency_names = libnarc diff --git a/tools/datagen/datagen.h b/tools/datagen/datagen.h index 59d1f09909..494f2ca5e5 100644 --- a/tools/datagen/datagen.h +++ b/tools/datagen/datagen.h @@ -6,23 +6,26 @@ * and packing programs. */ -// clang-format off #include +#include +#include #include #include #include #include #include +#include #include #include #include #include +// clang-format off +#include #include #include -#include "rapidjson/filewritestream.h" +#include #include -#include // clang-format on namespace fs = std::filesystem; @@ -124,29 +127,80 @@ static inline std::vector Tokenize(const std::string &s, const char return tokens; } -// Pack a NARC to an output path from a VFS context. -static inline void PackNarc(vfs_pack_ctx *ctx, fs::path path) -{ - narc *narc = narc_pack(ctx); +// Wrapper class around nitroarc's packing API +class NarcBuilder { + nitroarc_packer_t packer = { 0 }; - std::ofstream ofs(path); - ofs.write(reinterpret_cast(narc), narc->size); + static void* libc_malloc(void *ctx, unsigned items, unsigned size) { + (void)ctx; - free(narc); -} - -// Pack a single-file NARC of binary elements to an output path. -template -static inline void PackSingleFileNarc(std::vector &elems, fs::path path) -{ - if (elems.empty()) { - return; + return malloc(items * size); } - vfs_pack_ctx *vfs = narc_pack_start(); - narc_pack_file_copy(vfs, reinterpret_cast(elems.data()), sizeof(elems[0]) * elems.size()); - PackNarc(vfs, path); -} + static void libc_free(void *ctx, void *ptr, unsigned items, unsigned size) { + (void)ctx; + (void)items; + (void)size; + + free(ptr); + } + + static void* libc_realloc(void *ctx, void *ptr, unsigned items, unsigned size) { + (void)ctx; + + return realloc(ptr, items * size); + } + +public: + NarcBuilder(std::size_t num_files, bool named = false, bool stripped = false) { + packer.malloc = libc_malloc; + packer.realloc = libc_realloc; + packer.free = libc_free; + + if (int errc = nitroarc_pinit(&this->packer, num_files, named, stripped); errc) { + throw std::runtime_error(nitroarc_errs(errc)); + } + } + + struct Span { + std::byte *ptr; + u32 size; + }; + + void append(std::byte *ptr, u32 size, char *name = nullptr) { + if (int errc = nitroarc_ppack(&this->packer, ptr, size, name); errc) { + throw std::runtime_error(nitroarc_errs(errc)); + } + } + + void append(Span &span, char *name = nullptr) { append(span.ptr, span.size, name); } + + Span build() { + void *result = nullptr; + u32 size = 0; + if (int errc = nitroarc_pseal(&this->packer, &result, &size); errc) { + throw std::runtime_error(nitroarc_errs(errc)); + } + + return Span { reinterpret_cast(result), size }; + } + + void write(fs::path path) { + std::ofstream ofs(path); + Span narc = this->build(); + ofs.write(reinterpret_cast(narc.ptr), narc.size); + free(narc.ptr); + } + + template + static void write(std::vector &elems, fs::path path, char *name = nullptr) { + if (elems.empty()) return; + + NarcBuilder b { 1 }; + b.append(reinterpret_cast(elems.data()), sizeof(elems[0]) * elems.size(), name); + b.write(path); + } +}; // Read a whole file into a C++-string. static inline std::string ReadWholeFile(std::ifstream &ifs) @@ -240,7 +294,8 @@ static inline void ReportJsonError(rapidjson::ParseResult ok, std::string &json, } } -static inline void CopyMessage(const rapidjson::Value &member, rapidjson::Value &outMessage, rapidjson::MemoryPoolAllocator<> &allocator) { +static inline void CopyMessage(const rapidjson::Value &member, rapidjson::Value &outMessage, rapidjson::MemoryPoolAllocator<> &allocator) +{ if (member.HasMember("en_US")) { if (member["en_US"].IsArray()) { rapidjson::Value strings(rapidjson::kArrayType); diff --git a/tools/datagen/datagen_events.cpp b/tools/datagen/datagen_events.cpp index 78c5f11276..a585dfc334 100644 --- a/tools/datagen/datagen_events.cpp +++ b/tools/datagen/datagen_events.cpp @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #include "datagen.h" @@ -85,4 +83,4 @@ int main(int argc, char **argv) byEventObjectsHeader.close(); return EXIT_SUCCESS; -} \ No newline at end of file +} diff --git a/tools/datagen/datagen_frontier.cpp b/tools/datagen/datagen_frontier.cpp index 17b398970c..1c17408b51 100644 --- a/tools/datagen/datagen_frontier.cpp +++ b/tools/datagen/datagen_frontier.cpp @@ -9,9 +9,10 @@ */ #include -#include #include +#include #include +#include #include "datagen.h" @@ -36,29 +37,23 @@ static void BuildFrontierMonLookupTable(const std::vector pokemonRe } } -static void ParseSetIDs(const rapidjson::Value &member, u16 *trdata) +static void PackFrontierTrainer(const rapidjson::Document &doc, NarcBuilder &builder) { - int i, numSets = 0; - for (const auto &value : member.GetArray()) { - trdata[2 + i++] = MapSetnameToId[value.GetString()]; - - if (value != "none_1") { - numSets++; - } - } - trdata[1] = numSets; -} - -static void PackFrontierTrainer(const rapidjson::Document &doc, vfs_pack_ctx *pl_btdtrVFS) -{ - int dataSize = 2 + doc["availableSets"].GetArray().Size(); - u16 trdata[dataSize] = { 0 }; + auto sets = doc["availableSets"].GetArray(); + int dataSize = 2 + sets.Size(); + std::vector trdata; + trdata.resize(dataSize, 0); trdata[0] = LookupConst(doc["class"].GetString(), TrainerClass); - ParseSetIDs(doc["availableSets"], trdata); + for (int i = 0; i < sets.Size(); i++) { + const auto &value = std::string(sets[i].GetString()); + if (value != "none_1") trdata[1]++; - narc_pack_file_copy(pl_btdtrVFS, reinterpret_cast(&trdata), sizeof(trdata)); + trdata[2 + i] = MapSetnameToId[value]; + } + + builder.append(reinterpret_cast(trdata.data()), trdata.size() * sizeof(u16)); } static void ParseMoves(const rapidjson::Value &moves, BattleFrontierPokemonData &data) @@ -129,8 +124,8 @@ int main(int argc, char **argv) BuildFrontierMonLookupTable(pokemonRegistry); - vfs_pack_ctx *pl_btdtrVFS = narc_pack_start(); - vfs_pack_ctx *pl_btdpmVFS = narc_pack_start(); + NarcBuilder pl_btdtr { trainerRegistry.size() }; + NarcBuilder pl_btdpm { pokemonRegistry.size() }; rapidjson::Document namesTextBank(rapidjson::kObjectType); namesTextBank.AddMember("key", 26501, namesTextBank.GetAllocator()); rapidjson::Document messagesTextBank(rapidjson::kObjectType); @@ -144,7 +139,7 @@ int main(int argc, char **argv) LoadJson(doc, trainerDataPath); try { - PackFrontierTrainer(doc, pl_btdtrVFS); + PackFrontierTrainer(doc, pl_btdtr); std::string trName = doc["name"].GetString(); rapidjson::Value nameMessage(rapidjson::kObjectType); @@ -187,16 +182,15 @@ int main(int argc, char **argv) try { BattleFrontierPokemonData pmdata = ParseFrontierPokemon(doc); - - narc_pack_file_copy(pl_btdpmVFS, reinterpret_cast(&pmdata), sizeof(pmdata)); + pl_btdpm.append(reinterpret_cast(&pmdata), sizeof(pmdata)); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; std::exit(EXIT_FAILURE); } } - PackNarc(pl_btdtrVFS, outputRoot / "pl_btdtr.narc"); - PackNarc(pl_btdpmVFS, outputRoot / "pl_btdpm.narc"); + pl_btdtr.write(outputRoot / "pl_btdtr.narc"); + pl_btdpm.write(outputRoot / "pl_btdpm.narc"); char writeBuffer[65536]; diff --git a/tools/datagen/datagen_species.cpp b/tools/datagen/datagen_species.cpp index c47dd16118..101b9355b8 100644 --- a/tools/datagen/datagen_species.cpp +++ b/tools/datagen/datagen_species.cpp @@ -34,6 +34,7 @@ */ #include #include +#include #include #include #include @@ -452,40 +453,32 @@ static void EmitIconPaletteData(rapidjson::Document &root, std::ofstream &ofs, s << ",\n"; } -static void PackHeights(vfs_pack_ctx *vfs, rapidjson::Document &root, u8 genderRatio) +static void PackHeights(NarcBuilder &builder, rapidjson::Document &root, u8 genderRatio) { - u8 *backFemale, *backMale, *frontFemale, *frontMale; const rapidjson::Value &backOffsets = root["back"]["y_offset"]; const rapidjson::Value &frontOffsets = root["front"]["y_offset"]; + std::byte backFemale, backMale, frontFemale, frontMale; u32 femaleSize = 1, maleSize = 1; if (genderRatio == GENDER_RATIO_FEMALE_ONLY) { - backMale = static_cast(malloc(0)); - frontMale = static_cast(malloc(0)); maleSize = 0; } else { - backMale = static_cast(malloc(1)); - frontMale = static_cast(malloc(1)); - *backMale = backOffsets["male"].GetUint(); - *frontMale = frontOffsets["male"].GetUint(); + backMale = static_cast(backOffsets["male"].GetUint()); + frontMale = static_cast(frontOffsets["male"].GetUint()); } if (genderRatio == GENDER_RATIO_MALE_ONLY || genderRatio == GENDER_RATIO_NO_GENDER) { - backFemale = static_cast(malloc(0)); - frontFemale = static_cast(malloc(0)); femaleSize = 0; } else { - backFemale = static_cast(malloc(1)); - frontFemale = static_cast(malloc(1)); - *backFemale = backOffsets["female"].GetUint(); - *frontFemale = frontOffsets["female"].GetUint(); + backFemale = static_cast(backOffsets["female"].GetUint()); + frontFemale = static_cast(frontOffsets["female"].GetUint()); } - narc_pack_file(vfs, backFemale, femaleSize); - narc_pack_file(vfs, backMale, maleSize); - narc_pack_file(vfs, frontFemale, femaleSize); - narc_pack_file(vfs, frontMale, maleSize); + builder.append(&backFemale, femaleSize); + builder.append(&backMale, maleSize); + builder.append(&frontFemale, femaleSize); + builder.append(&frontMale, maleSize); } static SpriteAnimFrame ParseSpriteAnimationFrame(const rapidjson::Value &frame) @@ -696,10 +689,10 @@ int main(int argc, char **argv) << "static const u8 sPokemonIconPaletteIndex[] = {\n"; // Prepare VFSes for each NARC to be output. - vfs_pack_ctx *personalVFS = narc_pack_start(); - vfs_pack_ctx *evoVFS = narc_pack_start(); - vfs_pack_ctx *wotblVFS = narc_pack_start(); - vfs_pack_ctx *heightVFS = narc_pack_start(); + NarcBuilder personal { speciesRegistry.size() }; + NarcBuilder evo { speciesRegistry.size() }; + NarcBuilder wotbl { speciesRegistry.size() }; + NarcBuilder height { 4 * SPECIES_EGG }; // NOTE: using SPECIES_EGG as an effective NatDex number std::vector palParkData; std::vector offspringData; std::vector speciesSpriteData; @@ -726,9 +719,9 @@ int main(int argc, char **argv) TryEmitFootprint(doc, species, footprint_sizes, footprint_types); EmitIconPaletteData(doc, iconPalettes, species, personalValue, iconRegistry); - narc_pack_file_copy(personalVFS, reinterpret_cast(&data), sizeof(data)); - narc_pack_file_copy(evoVFS, reinterpret_cast(&evos), sizeof(evos)); - narc_pack_file_copy(wotblVFS, reinterpret_cast(&sizedLearnset.learnset), sizedLearnset.size); + personal.append(reinterpret_cast(&data), sizeof(data)); + evo.append(reinterpret_cast(&evos), sizeof(evos)); + wotbl.append(reinterpret_cast(&sizedLearnset.learnset), sizedLearnset.size); if (palPark.has_value()) { palParkData.emplace_back(palPark.value()); @@ -748,7 +741,7 @@ int main(int argc, char **argv) } u8 genderRatio = species != "none" ? data.genderRatio : GENDER_RATIO_FEMALE_50; // treat SPECIES_NONE as if it has two genders. - PackHeights(heightVFS, doc, genderRatio); + PackHeights(height, doc, genderRatio); SpeciesSpriteData speciesSprite = ParseSpeciesSpriteData(doc); speciesSpriteData.emplace_back(speciesSprite); @@ -786,12 +779,13 @@ int main(int argc, char **argv) << "#endif // POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H\n"; iconPalettes.close(); - PackNarc(personalVFS, outputRoot / "pl_personal.narc"); - PackNarc(evoVFS, outputRoot / "evo.narc"); - PackNarc(wotblVFS, outputRoot / "wotbl.narc"); - PackNarc(heightVFS, outputRoot / "height.narc"); - PackSingleFileNarc(palParkData, outputRoot / "ppark.narc"); - PackSingleFileNarc(speciesSpriteData, outputRoot / "pl_poke_data.narc"); + personal.write(outputRoot / "pl_personal.narc"); + evo.write(outputRoot / "evo.narc"); + wotbl.write(outputRoot / "wotbl.narc"); + height.write(outputRoot / "height.narc"); + + NarcBuilder::write(palParkData, outputRoot / "ppark.narc"); + NarcBuilder::write(speciesSpriteData, outputRoot / "pl_poke_data.narc"); PackOffspring(offspringData, outputRoot / "pms.narc"); return EXIT_SUCCESS; } diff --git a/tools/datagen/datagen_trainer.cpp b/tools/datagen/datagen_trainer.cpp index d5dbadc45f..c0c1b5cbbe 100644 --- a/tools/datagen/datagen_trainer.cpp +++ b/tools/datagen/datagen_trainer.cpp @@ -4,18 +4,25 @@ * Usage: datagen-species * * This program is responsible for generating data archives from trainer data - * files (res/trainers/data/*.json). The file-names to be polled for data are + * files (res/trainers/data/.json). The file-names to be polled for data are * drawn from an environment var TRAINERS, which should be a semicolon-delimited * list of file-stems. * * The following files are generated by this program: * - trdata.narc * - trpoke.narc + * - trtbl.narc + * - trtblofs.narc + * - npc_trainer_messages.json + * - npc_trainer_names.json */ +#include +#include #include #include #include #include +#include #include "datagen_trainer.h" #include "datagen.h" @@ -38,12 +45,12 @@ #include "struct_defs/trainer_data.h" -static void PackImmediately(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp); -static void ParseMovesAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp); -static void ParseItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp); -static void ParseMovesAndItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp); +static void PackImmediately(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp); +static void ParseMovesAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp); +static void ParseItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp); +static void ParseMovesAndItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp); -typedef std::function TrainerMonSubparser; +typedef std::function TrainerMonSubparser; struct TrainerDataTypeTable { TrainerMonSubparser subparser; @@ -114,12 +121,12 @@ static TrainerHeader ParseTrainerData(const rapidjson::Document &doc) return trdata; } -static void PackImmediately(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp) +static void PackImmediately(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp) { memcpy(bufp, &base, sizeof(base)); } -static void ParseMovesAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp) +static void ParseMovesAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp) { TrainerMonWithMoves withMoves = {}; withMoves.ivScale = base.ivScale; @@ -135,7 +142,7 @@ static void ParseMovesAndPack(const rapidjson::Value &member, TrainerMonBase &ba memcpy(bufp, &withMoves, sizeof(withMoves)); } -static void ParseItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp) +static void ParseItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp) { TrainerMonWithItem withItem = {}; withItem.ivScale = base.ivScale; @@ -148,7 +155,7 @@ static void ParseItemAndPack(const rapidjson::Value &member, TrainerMonBase &bas memcpy(bufp, &withItem, sizeof(withItem)); } -static void ParseMovesAndItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, unsigned char *bufp) +static void ParseMovesAndItemAndPack(const rapidjson::Value &member, TrainerMonBase &base, std::byte *bufp) { TrainerMonWithMovesAndItem withMovesAndItem = {}; withMovesAndItem.ivScale = base.ivScale; @@ -166,11 +173,11 @@ static void ParseMovesAndItemAndPack(const rapidjson::Value &member, TrainerMonB memcpy(bufp, &withMovesAndItem, sizeof(withMovesAndItem)); } -static void ParseAndPackParty(const rapidjson::Document &doc, TrainerDataType monDataType, std::size_t partySize, vfs_pack_ctx *trpokeVFS) +static void ParseAndPackParty(const rapidjson::Document &doc, TrainerDataType monDataType, std::size_t partySize, NarcBuilder &trpokeBuilder) { if (partySize == 0) { - unsigned char *buf = (unsigned char *)calloc(8, 1); - narc_pack_file(trpokeVFS, buf, 8); + static constexpr std::array sEmptyParty = {}; + trpokeBuilder.append(const_cast(sEmptyParty.data()), sEmptyParty.size()); return; } @@ -179,9 +186,10 @@ static void ParseAndPackParty(const rapidjson::Document &doc, TrainerDataType mo std::size_t bufSize = monSize * partySize; bufSize = bufSize + (-bufSize & 3); // align to 4-byte boundary - unsigned char *partyBuf = (unsigned char *)calloc(bufSize, 1); - unsigned char *partyBufp = partyBuf; + std::byte *partyBuf = new std::byte[bufSize]; + std::byte *partyBufp = partyBuf; + std::memset(partyBuf, 0, bufSize); for (const auto &member : doc["party"].GetArray()) { TrainerMonBase base = {}; base.ivScale = member["iv_scale"].GetUint(); @@ -194,7 +202,8 @@ static void ParseAndPackParty(const rapidjson::Document &doc, TrainerDataType mo partyBufp += monSize; } - narc_pack_file(trpokeVFS, partyBuf, bufSize); + trpokeBuilder.append(partyBuf, bufSize); + delete[] partyBuf; } static std::string ParseMessages(const rapidjson::Document &doc, int trainerID, std::string stem, rapidjson::Value *outMessages, rapidjson::Document *messagesTextBank) @@ -261,16 +270,16 @@ int main(int argc, char **argv) fs::path dataRoot = argv[2]; std::vector trainerRegistry = ReadRegistryEnvVar("TRAINERS"); - const int trainerCount = trainerRegistry.size(); + const std::size_t trainerCount = trainerRegistry.size(); std::string *trMsgs = new std::string[trainerCount]; short *trMsgOffsets = new short[trainerCount]; int *order = new int[trainerCount]; rapidjson::Value *messagesArr = new rapidjson::Value[trainerCount]; - vfs_pack_ctx *trdataVFS = narc_pack_start(); - vfs_pack_ctx *trpokeVFS = narc_pack_start(); - vfs_pack_ctx *trtblVFS = narc_pack_start(); - vfs_pack_ctx *trtblofsVFS = narc_pack_start(); + NarcBuilder trdataBuilder { trainerCount }; + NarcBuilder trpokeBuilder { trainerCount }; + NarcBuilder trtblBuilder { 1 }; + NarcBuilder trtblofsBuilder { 1 }; rapidjson::Document doc; rapidjson::Document messagesTextBank(rapidjson::kObjectType); @@ -292,8 +301,8 @@ int main(int argc, char **argv) try { TrainerHeader trdata = ParseTrainerData(doc); - narc_pack_file_copy(trdataVFS, reinterpret_cast(&trdata), sizeof(trdata)); - ParseAndPackParty(doc, static_cast(trdata.monDataType), trdata.partySize, trpokeVFS); + trdataBuilder.append(reinterpret_cast(&trdata), sizeof(trdata)); + ParseAndPackParty(doc, static_cast(trdata.monDataType), trdata.partySize, trpokeBuilder); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; std::exit(EXIT_FAILURE); @@ -337,7 +346,7 @@ int main(int argc, char **argv) namesTextBank.AddMember("messages", nameMessages, namesTextBank.GetAllocator()); std::string str = ""; - int offset = 0; + std::size_t offset = 0; rapidjson::Value messages(rapidjson::kArrayType); for (int i = 0; i < trainerCount; i++) { str += trMsgs[i]; @@ -355,13 +364,13 @@ int main(int argc, char **argv) messagesTextBank.AddMember("messages", messages, messagesTextBank.GetAllocator()); char *chars = const_cast(str.c_str()); - narc_pack_file_copy(trtblVFS, reinterpret_cast(chars), offset); - narc_pack_file_copy(trtblofsVFS, reinterpret_cast(trMsgOffsets), trainerCount * sizeof(short)); + trtblBuilder.append(reinterpret_cast(chars), offset); + trtblofsBuilder.append(reinterpret_cast(trMsgOffsets), trainerCount * sizeof(short)); - PackNarc(trdataVFS, outputRoot / "trdata.narc"); - PackNarc(trpokeVFS, outputRoot / "trpoke.narc"); - PackNarc(trtblVFS, outputRoot / "trtbl.narc"); - PackNarc(trtblofsVFS, outputRoot / "trtblofs.narc"); + trdataBuilder.write(outputRoot / "trdata.narc"); + trpokeBuilder.write(outputRoot / "trpoke.narc"); + trtblBuilder.write(outputRoot / "trtbl.narc"); + trtblofsBuilder.write(outputRoot / "trtblofs.narc"); char writeBuffer[65536]; diff --git a/tools/datagen/meson.build b/tools/datagen/meson.build index dd886faf11..63bdc71e64 100644 --- a/tools/datagen/meson.build +++ b/tools/datagen/meson.build @@ -7,11 +7,8 @@ # by standard depfile management and trigger a recompilation, which will then flag # files generated by the recompiled utilities for rebuild. -subproject('narc') subproject('rapidjson') -libnarc_dep = dependency('libnarc') - datagen_cpp_args = [ '-std=c++17', '-Wno-deprecated-declarations', # rapidjson 1.1.0 makes use of std::iterator @@ -32,7 +29,7 @@ datagen_species_exe = executable( toplevel_includes, ], dependencies: [ - libnarc_dep, + nitroarc_dep, rapidjson_dep, ], native: true, @@ -51,7 +48,7 @@ datagen_trainer_exe = executable( toplevel_includes, ], dependencies: [ - libnarc_dep, + nitroarc_dep, rapidjson_dep, ], native: true, @@ -70,7 +67,7 @@ datagen_frontier_exe = executable( toplevel_includes, ], dependencies: [ - libnarc_dep, + nitroarc_dep, rapidjson_dep, ], native: true, @@ -89,8 +86,8 @@ datagen_events_exe = executable( toplevel_includes, ], dependencies: [ - libnarc_dep, + nitroarc_dep, rapidjson_dep, ], native: true, -) \ No newline at end of file +) diff --git a/tools/devtools/gen_compile_commands.py b/tools/devtools/gen_compile_commands.py index 3a565f52c2..1d3f1d7d43 100755 --- a/tools/devtools/gen_compile_commands.py +++ b/tools/devtools/gen_compile_commands.py @@ -296,13 +296,34 @@ c_commands = [ for file in (homedir / "src").rglob("*.c") ] +nitroarc_c_commands = [ + { + "directory": builddir, + "arguments": [ + "gcc", + f"-I{homedir}/tools/nitroarc/lib/include", + "-std=c99", + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wconversion", + "-Wno-sign-conversion", + "-o", + file.with_suffix(".o"), + file.resolve(), + ], + "file": file.resolve(), + } + for file in (homedir / "tools" / "nitroarc").rglob("*.c") +] + datagen_cpp_commands = [ { "directory": builddir, "arguments": [ "g++", - f"-I{homedir}/subprojects/narc/lib/include", # NARC packing f"-I{homedir}/subprojects/rapidjson-1.1.0/include", # JSON parser + f"-I{homedir}/tools/nitroarc/lib/include", # NARC packing f"-I{homedir}/tools/datagen", # base header file f"-I{homedir}/include", # source includes f"-I{builddir}", # metang-generated headers (constants) @@ -328,7 +349,8 @@ with open("compile_commands.json", "w") as ofp: + libcrypto_c_commands + ppwlobby_c_commands + c_commands - + datagen_cpp_commands, + + datagen_cpp_commands + + nitroarc_c_commands, ofp, default=str, indent=4, diff --git a/tools/jsoncnv/jsoncnv.py b/tools/jsoncnv/jsoncnv.py index e252a0a619..17d7ea4626 100644 --- a/tools/jsoncnv/jsoncnv.py +++ b/tools/jsoncnv/jsoncnv.py @@ -228,7 +228,7 @@ def jsoncnv(target: str, binaries[output_idx] = output_bin elif output_mode == OutputMode.MULTI_FILE: _write(output_bin, output_idx, private_dir) - + if output_mode == OutputMode.SINGLE_FILE: merged = bytearray([]) for idx in sorted(binaries.keys()): @@ -236,7 +236,8 @@ def jsoncnv(target: str, _write(merged, 0, private_dir) subprocess.run([ - pathlib.Path(narc_packer), 'create', - '--output', output_dir / f'{narc_name}.narc', + pathlib.Path(narc_packer), + '--create', + '--file', output_dir / f'{narc_name}.narc', private_dir, ]) diff --git a/tools/meson.build b/tools/meson.build index edc8ab505a..72a0e56b0d 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -1,6 +1,7 @@ rapidjson_dep = dependency('rapidjson') # Native tools +subdir('nitroarc') # Contains a library component that other tools depend on subdir('csv2bin') subdir('datagen') subdir('fixrom') @@ -21,5 +22,4 @@ arm_none_eabi_objcopy_exe = find_program('arm-none-eabi-objcopy', native: true) # Subproject tools makelcf_exe = find_program('makelcf', native: true) nitrorom_exe = find_program('nitrorom', native: true) -narc_exe = find_program('narc', native: true) SDATTool_py = find_program('SDATTool_py', native: true) diff --git a/tools/nitroarc/README.md b/tools/nitroarc/README.md new file mode 100644 index 0000000000..81325b189b --- /dev/null +++ b/tools/nitroarc/README.md @@ -0,0 +1,25 @@ +`nitroarc` +========== + +An implementation of the Nitro Archive file format used by the Nintendo DS. + +This tooling is split into two core components: a C library implementing the +archive format specification and a command-line program for inspecting and +manipulating archives. + +Usage +----- + +The library header aims to be well-documented and cover most of the use-cases +associated with manipulating archive files. Example code for the basics is +available in [the library documentation](./doc/nitroarc.3.adoc). + +The command-line tool provides help-text (`nitroarc --help`) containing a list +of available options, a summary of each option's functionality, and examples +illustrating rudimentary invocation. [A program manual](./doc/nitroarc.1.adoc) +provides detailed information on the various execution modes. + +Contributing +------------ + +Please report bugs and submit patches to [the upstream repository](https://codeberg.org/lhearachel/nitroarc). diff --git a/tools/nitroarc/doc/nitroarc.1.adoc b/tools/nitroarc/doc/nitroarc.1.adoc new file mode 100644 index 0000000000..f2c6280d09 --- /dev/null +++ b/tools/nitroarc/doc/nitroarc.1.adoc @@ -0,0 +1,167 @@ +nitroarc (1) +============ + +:doctype: manpage +:manmanual: General Commands Manual +:mansource: NitroARC Manual +:source-highlighter: rouge + +Name +---- + +nitroarc - an archiving utility for Nintendo's Nitro Archive format + +Synopsis +-------- + +*nitroarc* *-cf* _ARCHIVE_ [*-INRS*] [*-E _PATTERN_*] [*-X _FILE_*] [*-T _FILE_*] _DIRECTORY_ + +*nitroarc* *-mf* _ARCHIVE_ [*-H*] [*-F _FORMAT_*] + +*nitroarc* *-tf* _ARCHIVE_ [*-H*] [*-F _FORMAT_*] + +*nitroarc* *-xf* _ARCHIVE_ [_DIRECTORY_] + + +Description +----------- + +*nitroarc* is an archiving utility which targets the Nitro Archive format for +the Nintendo DS handheld. This tool is a minimal front-end for users and build +systems. Programmers building applications that target the format may reference +*nitroarc(3)*. + +*nitroarc* is a modal utility; functionality is controlled by specifying exactly +one of the following flags: + +*-c, --create*:: + Create _ARCHIVE_ with the files in _DIRECTORY_. All files which descend from + _DIRECTORY_ or any of its subdirectories will be included in _ARCHIVE_. + +*-m, --meta, --metadata*:: + View tabulated metadata about the sections of _ARCHIVE_. + +*-t, --list*:: + List tabulated contents of _ARCHIVE_. When _ARCHIVE_ defines a filesystem, + the output table will list member files by their full paths with a preceding + forward-slash (‘/’). Otherwise, the output table will list member files as + they are ordered in _ARCHIVE_ and a best guess at the respective file-type. + +*-x, --extract*:: + Extract the contents of _ARCHIVE_ to _DIRECTORY_. When _DIRECTORY_ is not + given, it will default to _ARCHIVE_ suffixed by “.d”. When _ARCHIVE_ defines a + filesystem, both the directory tree and member file-paths will be mirrored, + with _DIRECTORY_ acting as the effective root. Otherwise, each member's image + will be written to a file named by its index in _ARCHIVE_ and an extension + appropriate to its file-type (as in *--list*). + +*-?, -h, --help*:: + Print a summary of program options and functionality. + +*-V, --version*:: + Print the program version and a copyright summary. + +Additional options may further control program output. Some are only supported +by specific operation modes; any options that are not supported by a mode are +silently ignored. Only the last-specified instance of each option will be +evaluated. + +=== Common Options === + +*-C _DIRECTORY_, --create=_DIRECTORY_*:: + Change the program's working directory before performing any other actions. + This option is always evaluated before any other options or arguments. + +*-v, --verbose*:: + Write additional logging statements to the standard error stream during + execution. + +=== Controlling Archive Creation === + +*-E _PATTERN_, --exclude=_PATTERN_*:: + Exclude files with names matching _PATTERN_ while scanning _DIRECTORY_ for + potential members. Matches are evaluated using the same globbing rules as + *fnmatch(3)*. This pattern is *not* evaluated against member files which are + included using *--files-from*. To specify more than a single pattern, use + *--exclude-from*. + +*-X _FILE_, --exclude-from=_FILE_*:: + Read lines from _FILE_ to be evaluated as exclusion patterns for potential + members, as in *--exclude*. + +*-T _FILE_, --files-from=_FILE_*:: + Read lines from _FILE_ as the names of files to be included as members in + _ARCHIVE_. Members specified in this manner are added to _ARCHIVE_ in the same + ordering as they are listed in _FILE_. After all such members have been + included, execution will proceed to scanning _DIRECTORY_ for other potential + members in the usual manner, skipping those which were already added by this + option. + +*-I, --index*:: + Output a C header for _ARCHIVE_ to a file-path mirroring _ARCHIVE_ with its + extension replaced by “.naix”. C programs may use this header to map relative + paths from the local filesystem to their indices in _ARCHIVE_ via preprocessor + “#define” statements. Any character in the local path for a member file which + is neither an alphanumeric ASCII character nor an ASCII underscore (‘_’) will + be replaced by an ASCII underscore in the respective preprocessor token. e.g., + a member file located at “/path/to/file” will write “#define path_to_file”, + followed by a single ASCII space (‘ ’) and its member index on the same line. + +*-N, --named*:: + Mirror the local filesystem from _DIRECTORY_ in _ARCHIVE_, with _DIRECTORY_ + acting as the effective root. Additionally, the behavior of *--files-from* is + altered such that any listed file-path is only included once. + +*-R, --no-recursion*:: + Do not traverse subdirectories of _DIRECTORY_ for potential members. + +*-S, --stripped*:: + Write _ARCHIVE_ as a “stripped” variant. The typical header will be replaced + by a minimal header specifying only the local byte-offsets and sizes of the + FNTB and FATB sections, and all byte-offsets listed in the FATB section will + be written as absolute values rather than values relative to the start of the + FIMG section. + +=== Formatting Tabulated Output === + +*-F _FORMAT_, --format=_FORMAT_*:: + Write tabulated data using _FORMAT_. Defaults to “markdown”. Recognized values + are “markdown” and “csv”. + +*-H, --no-header*:: + Do not write the header row(s) for the output format. When writing output as + Markdown, this also removes the explicit cell-alignment row which would be + included between the header cells and the first row of data cells; such output + may thus be evaluated as a sequence of pipe-delimited rows. + +Exit Status +----------- + +The *nitroarc* utility exits 0 on success, and >0 if an error occurs. + +Examples +-------- + +[source,bash,indent=0] +---- +# Create archive.narc using all files in path/to/directory. +nitroarc -cf archive.narc path/to/directory + +# Mirror the filesystem tree under path/to/directory in the created archive. +nitroarc -cNf archive.narc path/to/directory + +# Write a stripped archive. +nitroarc -cNSf archive.narc path/to/directory + +# View the members of archive.narc in CSV format. +nitroarc -tf archive.narc -F csv + +# Dump the members of archive.narc to archive.narc.d. +nitroarc -xf archive.narc +---- + +See Also +-------- + +*nitroarc(3)*, *fnmatch(3)* + +Contributions +------------- + +Report bugs and submit patches to . diff --git a/tools/nitroarc/doc/nitroarc.3.adoc b/tools/nitroarc/doc/nitroarc.3.adoc new file mode 100644 index 0000000000..86d3f138ae --- /dev/null +++ b/tools/nitroarc/doc/nitroarc.3.adoc @@ -0,0 +1,165 @@ +nitroarc (3) +============ + +:doctype: manpage +:manmanual: Library Functions Manual +:mansource: NitroARC Manual +:man-linkstyle: pass:[blue R < >] +:source-highlighter: rouge + +Name +---- + +nitroarc - implementation of Nintendo's Nitro Archive format + +Library +------- + +nitroarc (_libnitroarc_, _-lnitroarc_) + +Synopsis +-------- + +[source,c] +---- +#include + +typedef struct nitroarc nitroarc_t; + +int nitroarc_read(const void *stream, size_t size, nitroarc_t *out_narc); + +int nitroarc_geti(const nitroarc_t *narc, uint16_t i, + void **out_member, size_t *out_size); + +int nitroarc_gets(const nitroarc_t *narc, const char *s, + void **out_member, size_t *out_size); + +int nitroarc_nameof(const nitroarc_t *narc, uint16_t i, char *buf, size_t size); + +typedef struct nitroarc_packer nitroarc_packer_t; +struct nitroarc_packer { + void *ctx; + void* (*malloc)(void *ctx, unsigned items, unsigned size); + void* (*realloc)(void *ctx, void *ptr, unsigned items, unsigned size); + void (*free)(void *ctx, void *ptr, unsigned items, unsigned size); +}; + +int nitroarc_pinit(nitroarc_packer_t *p, uint16_t nfiles, + unsigned named, unsigned stripped); + +int nitroarc_ppack(nitroarc_packer_t *p, void *data, uint32_t size, char *name); + +int nitroarc_pseal(nitroarc_packer_t *p, void **out_data, uint32_t *out_size); + +const char* nitroarc_errs(int errc); +---- + +Description +----------- + +*nitroarc* is a C library implementing the Nitro Archive file format for the +Nintendo DS handheld. The library provides routines for decoding an archive from +an arbitrary stream of bytes, accessing members from a decoded archive, and +constructing an archive with particular members. + +The archive-decoding and member-access routines are implemented as zero-copy +functions. _nitroarc_read()_ writes a set of pointers and simple primitives as +interpreted from the provided byte-stream; thus, any dynamic allocation for the +byte-stream must maintain the same lifetime as the decoded structure. This rule +also applies to the buffers written to by _nitroarc_geti()_, _nitroarc_gets()_, +and _nitroarc_nameof()_. + +The archive-construction routines require access to a dynamic memory-allocation +interface. This interface must be defined in the _nitroarc_packer_t_ structure +before it is passed to _nitroarc_pinit()_. An example implementation of this +interface using the standard *malloc(3)* routines is provided below. + +Return Value +------------ + +With the exception of _nitroarc_errs()_, all library functions return 0 on +success, and >0 if an error occurs. + +_nitroarc_errs()_ returns a pointer to a statically-allocated, null-terminated +string describing the input error code. If the error code is unrecognized, then +a pointer to a default error message will be returned. Programmers should not +attempt to pass any value returned by this function a any _free()_-like routine. + +Examples +-------- + +=== Decoding an Existing Archive === + +[source,c] +---- +#include +#include + +extern int read_file(const char *filename, char **out_data, uint32_t *out_size); + +static nitroarc_t read_archive(const char *target) { + nitroarc_t archive; + char *data = NULL; + uint32_t size = 0; + + read_file(target, &data, &size); + nitroarc_read(data, size, &archive); + return archive; +} +---- + +=== Constructing a New Archive === + +[source,c] +---- +#include +#include +#include + +static void* libc_malloc(void *ctx, unsigned items, unsigned size) { + return malloc(items * size); +} + +static void libc_free(void *ctx, void *ptr, unsigned items, unsigned size) { + free(ptr); +} + +static void* libc_realloc(void *ctx, void *ptr, unsigned items, unsigned size) { + return realloc(ptr, items * size); +} + +extern int read_file(const char *filename, char **out_data, uint32_t *out_size); +extern int write_file(const char *filename, const char *data, uint32_t size); + +static void make_archive(const char *target, const char **members, int count) { + nitroarc_packer_t packer; + packer.malloc = libc_malloc; + packer.realloc = libc_realloc; + packer.free = libc_free; + + char *data = NULL; + uint32_t size = 0; + + nitroarc_pinit(&packer, count, false, false); + + for (int i = 0; i < count; i++) { + load_file(members[i], &data, &size); + nitroarc_ppack(&packer, data, size, members[i]); + free(data); + } + + nitroarc_pseal(&packer, &data, &size); + write_file(target, data, size); + free(data); +} +---- + +See Also +-------- + +*nitroarc(1)*, *malloc(3)* + +Contributions +------------- + +Report bugs and submit patches to . diff --git a/tools/nitroarc/lib/include/nitroarc.h b/tools/nitroarc/lib/include/nitroarc.h new file mode 100644 index 0000000000..07c1e050a9 --- /dev/null +++ b/tools/nitroarc/lib/include/nitroarc.h @@ -0,0 +1,236 @@ +/* + * #include - implementation of Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This library is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef NITROARC_H +#define NITROARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct nitroarc_fatb nitroarc_fatb_t; +struct nitroarc_fatb { + uint32_t ofs_head; + uint32_t ofs_data; + uint32_t size; + + const void *data; +}; + +typedef struct nitroarc_fntb nitroarc_fntb_t; +struct nitroarc_fntb { + uint32_t ofs_head; + uint32_t ofs_data; + uint32_t size; + + const void *data; +}; + +typedef struct nitroarc_fimg nitroarc_fimg_t; +struct nitroarc_fimg { + uint32_t ofs_head; + uint32_t ofs_data; + uint32_t size; + + const void *data; +}; + +typedef struct nitroarc nitroarc_t; +struct nitroarc { + uint32_t size; + uint16_t nfiles; + uint16_t ndirs; + + const void *head; + nitroarc_fatb_t fatb; + nitroarc_fntb_t fntb; + nitroarc_fimg_t fimg; +}; + +/* + * Read an arbitrary byte-stream according to the NitroARC file format. + * + * The incoming byte-stream `stream` is assumed to be untrusted, and this + * routine will validate it against the file format's binary schema. If any + * invariant of the schema is unsatisfied, then the provided `narc` structure + * handle will be filled with zeroes and a non-zero error code will be returned. + * + * The resulting `narc` is computed using zero allocations, and the owner of + * the byte-stream maintains responsibility for freeing it. Any other operations + * against a `narc` that has had any of its memory-pointers invalidated shall + * result in undefined behavior. + */ +int nitroarc_read(const void *stream, uint32_t size, nitroarc_t *out_narc); + +/* + * Get the image data for an archive member with a given integer index. + * + * If `i` is some value greater than the number of members present in the + * archive, then a non-zero error code will be returned. If neither `out_member` + * nor `out_size` are `NULL`, this routine will store a pointer to the image + * data in `*out_member` and the size of the image data in bytes in `*out_size`. + */ +int nitroarc_geti(const nitroarc_t *narc, uint16_t i, void **out_member, uint32_t *out_size); + +/* + * Get the image data for an archive member with a given virtual filepath. + * + * If `s` is `NULL` or does not match the filepath of some member of the + * archive, then a non-zero error code will be returned. If neither `out_member` + * nor `out_size` are `NULL`, this routine will store a pointer to the image + * data in `*out_member` and the size of the image data in bytes in `*out_size`. + * + * The value of `s` is interpreted as a null-terminated Unix-style filepath + * using `'/'` as the directory separator. `s[0]` must be `'/'`, and the final + * character before the terminator must NOT be `'/'`. + */ +int nitroarc_gets(const nitroarc_t *narc, const char *s, void **out_member, uint32_t *out_size); + +/* + * Get the name of an archive member with a given integer index. + * + * The input buffer `buf` will be filled with the archive member's filesystem + * path. At most `size` characters will be printed into `buf`, including the + * zero-terminator. + * + * If `i` is some value greater than the number of members present in the + * archive, then a non-zero error code will be returned. If the input archive + * does not record file-names, then `buf` will not be modified, and this routine + * will return 0. + */ +int nitroarc_nameof(const nitroarc_t *narc, uint16_t i, char *buf, size_t size); + +enum { + NITROARC_ESUCCESS = 0, + NITROARC_ENULL, + NITROARC_ESIZERANGE, + NITROARC_ESIGNATURE, + NITROARC_EBYTEORDER, + NITROARC_EVERSION, + NITROARC_EARCHIVESIZE, + NITROARC_EHEADERSIZE, + NITROARC_ESECTIONS, + NITROARC_ENUMFILES, + NITROARC_EFATBSIG, + NITROARC_EFATBSIZE, + NITROARC_EFNTBSIG, + NITROARC_EFNTBSIZE, + NITROARC_EFIMGSIG, + NITROARC_EFIMGSIZE, + NITROARC_EINDEXDIR, + NITROARC_EINDEXRANGE, + NITROARC_EINVALIDPATH, + NITROARC_ENOSUCHFILE, + + NITROARC_EALLOCDEF, + NITROARC_EALLOCFAIL, + NITROARC_ETOOMANYFILES, + NITROARC_ESIZEOVERFLOW, + NITROARC_EINVALIDNAME, + + NITROARC_EMAX, // Reserved for internal use +}; + +/* + * Get a printable, user-facing error message for a library error. + * + * If `errc` is not recognized, then a standard message will be emitted. + */ +const char* nitroarc_errs(int errc); + +#ifndef NITROARC_DISABLE_PACKING_API // Define this to disable the packing API + +typedef struct nitroarc_file nitroarc_file_t; +typedef struct nitroarc_packer nitroarc_packer_t; +struct nitroarc_packer { + void *fimg_data; // buffer of packed file images + uint32_t fimg_size; // size of the image buffer + uint32_t fimg_capacity; // byte-capacity of the image buffer + + nitroarc_file_t *f_records; // records for packed files + uint16_t f_count; // number of files packed so far + uint16_t f_capacity; // number of files, maximum + + uint32_t flags; // control flags + + // memory interface + void *ctx; + void* (*malloc)(void *ctx, unsigned items, unsigned size); + void* (*realloc)(void *ctx, void *ptr, unsigned items, unsigned size); + void (*free)(void *ctx, void *ptr, unsigned items, unsigned size); +}; + +/* + * Initialize an encoder with a known number of file images. + * + * The packing interface must be initialized with an allocation interface before + * invoking this routine. + * + * If `named` is given as any value other than 0, then the initialized encoder + * will output a filesystem table which enables lookup of member files by their + * local names. Otherwise, the names of individual member files shall be + * stripped from the final archive, and member files will only be accessible via + * direct access by their indices. + * + * If `stripped` is given as any value other than 0, then the initialized + * encoder will output an archive which does not contain a NARC-signed header. + * + * Any names provided for encoding are *not* owned by this API; if they are + * dynamically-allocated, then the calling code assumes responsibility for + * freeing them. + * + * If the value of `nfiles` is equal to 0 or is greater than 61,440, then a + * non-zero error code will be returned denoting that too many files are + * expected for packing. + */ +int nitroarc_pinit(nitroarc_packer_t *p, uint16_t nfiles, unsigned named, unsigned stripped); + +/* + * Pack a (possibly named) file-image into the encoder. + * + * When serialized, the resulting block of member file-images will be ordered + * identically to the order in which they were packed into the encoder. If the + * encoder was initialized with `named == 0`, then this ordering will also + * mirror the ordering of filesystem IDs assigned to each member-file. + * + * If this encoder was initialized with `named == 0`, then it is safe to call + * this routine with `name = NULL`. + */ +int nitroarc_ppack(nitroarc_packer_t *p, void *data, uint32_t size, char *name); + +/* + * Seal the encoder into a serialized format. + * + * When successful, all memory which was dynamically-allocated by the encoder + * via the provided allocation interface will be released by that interface. + * + * If the resulting archive size would result in an overflow, then a non-zero + * error code will be returned. + */ +int nitroarc_pseal(nitroarc_packer_t *p, void **out_data, uint32_t *out_size); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NITROARC_H diff --git a/tools/nitroarc/lib/nitroarc.c b/tools/nitroarc/lib/nitroarc.c new file mode 100644 index 0000000000..0587b6c502 --- /dev/null +++ b/tools/nitroarc/lib/nitroarc.c @@ -0,0 +1,1070 @@ +/* + * #include - implementation of Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This library is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "nitroarc.h" + +#ifndef NITROARC_PRIVATE_H +#define NITROARC_PRIVATE_H + +#include +#include + +#define SIGNATURE_NARC 0x4352414E // "NARC" in little-endian +#define SIGNATURE_BTAF 0x46415442 // "BTAF" in little-endian +#define SIGNATURE_BTNF 0x464E5442 // "BTNF" in little-endian +#define SIGNATURE_GMIF 0x46494D47 // "GMIF" in little-endian + +#define BOM_BIGEND 0xFEFF +#define BOM_LITEND 0xFFFE + +#define NARC_VERSION 0x0100 +#define NARC_HEADERSIZE 0x10 +#define NARC_SECTIONS 0x03 + +#define NARC_MAXFILES 0xF000 + +#define FATB_HEADERSIZE 0x0C +#define FNTB_HEADERSIZE 0x08 +#define FIMG_HEADERSIZE 0x08 + +#define FATB_ENTRYSIZE (sizeof(uint32_t) * 2) + +#define FNTB_DIRTAB_ENTRYSIZE (sizeof(uint32_t) + (2 * sizeof(uint16_t))) +#define FNTB_FILESYS_MASKID 0x0FFF +#define FNTB_FILESYS_MASKTYPE 0xF000 + +#define FNTB_DIRENT_MASKSIZE 0x7F +#define FNTB_DIRENT_MASKTYPE 0x80 +#define FNTB_DIRENT_TYPEFILE 0x00 +#define FNTB_DIRENT_TYPEDIR 0x80 + +#define PACKCTL_ZERO 0 +#define PACKCTL_NAMED (1 << 0) +#define PACKCTL_STRIPPED (1 << 1) + +#define PACKCTL_ISNAMED(p) (((p)->flags & PACKCTL_NAMED) != 0) +#define PACKCTL_ISSTRIPPED(p) (((p)->flags & PACKCTL_STRIPPED) != 0) + +struct nitroarc_file { + char *name; + uint32_t offset; + uint32_t size; +}; + +static inline uint16_t leu16(const void *_s) { + const uint8_t *s = _s; + return (uint16_t)((s[1] << 8) | (s[0])); +} + +static inline uint32_t leu32(const void *_s) { + const uint8_t *s = _s; + return (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0]; +} + +static inline void putleu16(void *_s, uint16_t u) { + uint8_t *s = _s; + s[0] = ((unsigned)u >> 0) & 0xFF; + s[1] = ((unsigned)u >> 8) & 0xFF; +} + +static inline void putleu32(void *_s, uint32_t u) { + uint8_t *s = _s; + s[0] = (uint8_t)((u >> 0) & 0xFF); + s[1] = (uint8_t)((u >> 8) & 0xFF); + s[2] = (uint8_t)((u >> 16) & 0xFF); + s[3] = (uint8_t)((u >> 24) & 0xFF); +} + +#define align_u(u) (-(u) & 3) +#define align_u32(u) (-(u) & 31) +#define align_d(d) (-(uintptr_t)(d) & 3) + +static inline ptrdiff_t ptrdiff(const void *_l, const void *_r) { + const unsigned char *l = _l; + const unsigned char *r = _r; + + return l - r; +} + +static inline char* strchrnul(const char *_s, int _c) { + const unsigned char c = (unsigned char)_c; + const unsigned char *s = (void *)_s; + + while (*s && *s != c) s++; + return (char *)s; +} + +#endif // NITROARC_PRIVATE_H + +const char* errors[] = { + [NITROARC_ESUCCESS] = "success", + [NITROARC_ENULL] = "a required parameter is NULL", + [NITROARC_ESIZERANGE] = "input size is out-of-range", + [NITROARC_ESIGNATURE] = "archive has an invalid file signature", + [NITROARC_EBYTEORDER] = "archive has an invalid byte-order mark", + [NITROARC_EVERSION] = "archive has an unsupported version", + [NITROARC_EARCHIVESIZE] = "archive reports a different size from the input", + [NITROARC_EHEADERSIZE] = "archive has an invalid header size", + [NITROARC_ESECTIONS] = "archive has an invalid number of sections", + [NITROARC_ENUMFILES] = "archive member count does not align with its size", + [NITROARC_EFATBSIG] = "allocation table has an invalid section signature", + [NITROARC_EFATBSIZE] = "allocation table reports an invalid section size", + [NITROARC_EFNTBSIG] = "filename table has an invalid section signature", + [NITROARC_EFNTBSIZE] = "filename table reports an invalid section size", + [NITROARC_EFIMGSIG] = "file image table has an invalid section signature", + [NITROARC_EFIMGSIZE] = "file image table reports an invalid section size", + [NITROARC_EINDEXDIR] = "requested index would be a directory, not a file", + [NITROARC_EINDEXRANGE] = "requested index is greater than the number of members", + [NITROARC_EINVALIDPATH] = "requested filepath is improperly constructed", + [NITROARC_ENOSUCHFILE] = "no such member for the requested filepath", + [NITROARC_EALLOCDEF] = "allocation interface is improperly defined", + [NITROARC_EALLOCFAIL] = "allocation failure", + [NITROARC_ETOOMANYFILES] = "too many files expected", + [NITROARC_ESIZEOVERFLOW] = "output size exceeds 32-bit maximum", + + [NITROARC_EMAX] = "unknown error code", +}; + +const char* nitroarc_errs(int errc) { + errc = errc >= NITROARC_ESUCCESS && errc < NITROARC_EMAX + ? errc + : NITROARC_EMAX; + return errors[errc]; +} + +#include +#include + + +int nitroarc_geti(const nitroarc_t *narc, uint16_t i, void **out_member, uint32_t *out_size) { + if (narc == NULL) return NITROARC_ENULL; + if ((i & FNTB_FILESYS_MASKTYPE)) return NITROARC_EINDEXDIR; + if (narc->nfiles <= i) return NITROARC_EINDEXRANGE; + + if (out_member != NULL && out_size != NULL) { + const uint8_t *p_fatb = (uint8_t *)narc->fatb.data; + const uint8_t *p_fent = p_fatb + (i * FATB_ENTRYSIZE); + const uint32_t ofsbeg = leu32(p_fent); + const uint32_t ofsend = leu32(p_fent + sizeof(uint32_t)); + + *out_member = (uint8_t *)narc->fimg.data + ofsbeg; + *out_size = ofsend - ofsbeg; + } + + return NITROARC_ESUCCESS; +} + +#include +#include + + +// Similar to `strncmp`, but returns either `1` (if the strings are equivalent +// across a prefix of size `n`) or `0` (if they aren't). +// +// More formally: +// - `strnequ(l, r, n) == 1` is equivalent to `strncmp(l, r, n) == 0` +// - `strnequ(l, r, n) == 0` is equivalent to `strncmp(l, r, n) != 0` +static int strnequ(const char *_l, const char *_r, size_t n) { + const unsigned char *l = (void *)_l; + const unsigned char *r = (void *)_r; + + if (n == 0) return 1; // 0-length comparison is treated as "equal" + + for (n--; *l && *r && n && *l == *r; l++, r++, n--); + return *l == *r; +} + +#define skip_d() p_dirent += 3 + size; continue +#define skip_f() p_dirent += 1 + size; continue + +int nitroarc_gets(const nitroarc_t *narc, const char *s, void **out_member, uint32_t *out_size) { + if (narc == NULL) return NITROARC_ENULL; + if (s == NULL) return NITROARC_ENULL; + if (s[0] != '/') return NITROARC_EINVALIDPATH; + if (s[1] == '\0') return NITROARC_EINVALIDPATH; // Only search for leaves + + const char *p_path = &s[1]; + const char *p_dirsep = strchrnul(p_path, '/'); + size_t compsize = p_dirsep - p_path; + + const char *p_fntb = narc->fntb.data; + const char *p_dirtab = p_fntb; + const char *p_dirent = p_fntb + leu32(p_dirtab); + + uint16_t id_found = 0xFFFF; + uint16_t id = 0; + while (*p_dirent != 0 && id_found == 0xFFFF && id < FNTB_FILESYS_MASKTYPE) { + const uint8_t mask = *p_dirent; + const uint8_t type = mask & FNTB_DIRENT_MASKTYPE; + const uint8_t size = mask & FNTB_DIRENT_MASKSIZE; + + if (*p_dirsep == '/') { + if (type != FNTB_DIRENT_TYPEDIR) { skip_f(); } + if (strnequ(p_path, p_dirent + 1, compsize)) { skip_d(); } + + if (p_dirent[1] == '\0') return NITROARC_EINVALIDPATH; + + uint16_t id_subdir = leu16(p_dirent + 1 + compsize); + + p_dirtab = p_fntb + (id_subdir & FNTB_FILESYS_MASKID); + p_dirent = p_fntb + leu32(p_dirtab); + p_path = p_dirsep + 1; + p_dirsep = strchrnul(p_path, '/'); + compsize = p_dirsep - p_path; + id = leu16(p_dirtab + 4); + + continue; + } + + if (type != FNTB_DIRENT_TYPEFILE) { skip_d(); } + if (strnequ(p_path, p_dirent + 1, compsize)) { id++; skip_f(); } + + id_found = id; + } + + return *p_dirent != 0 + ? nitroarc_geti(narc, id_found, out_member, out_size) + : NITROARC_ENOSUCHFILE; +} + +#undef skip_d +#undef skip_f + +#include +#include +#include + + +#define skip_d() p_enttab += 3 + nlen; continue +#define skip_f() p_enttab += 1 + nlen; continue + +int nitroarc_nameof(const nitroarc_t *narc, uint16_t i, char *buf, size_t size) { + assert(narc); + assert(buf); + assert(size); + + if (narc->ndirs == 1) { + *buf = 0; + return NITROARC_ESUCCESS; + } + + if ((i & FNTB_FILESYS_MASKTYPE)) return NITROARC_EINDEXDIR; + if (narc->nfiles <= i) return NITROARC_EINDEXRANGE; + + char *p_buf = buf; + *p_buf++ = '/'; + + const char *p_fntb = narc->fntb.data; + const char *p_dirtab = p_fntb; + const char *p_enttab = p_fntb + leu32(p_dirtab); + const char *p_subent = NULL; + uint16_t i_firstf = 0; + +loopback: + while (*p_enttab != 0) { + const uint8_t mask = *p_enttab; + const uint8_t type = mask & FNTB_DIRENT_MASKTYPE; + const uint8_t nlen = mask & FNTB_DIRENT_MASKSIZE; + + if (type == FNTB_DIRENT_TYPEFILE) { + if (i_firstf < i) { i_firstf++; skip_f(); } + + for (uint8_t j = 0; j < nlen && size > 1; j++, size--) { + *p_buf++ = *++p_enttab; + } + *p_buf = 0; + return NITROARC_ESUCCESS; + } + + // If this directory says it has a file with ID less than or equal to + // the requested file, then the pointer to its subdirectory entry. + uint16_t dirid = leu16(&p_enttab[1 + nlen]) & FNTB_FILESYS_MASKID; + const char *p_ent = p_fntb + (FNTB_DIRTAB_ENTRYSIZE * dirid); + uint16_t first = leu16(&p_ent[4]); + if (first <= i) p_subent = p_enttab; + + skip_d(); + } + + + // The last-recorded subdirectory is the next destination; copy its name, + // then continue. + if (p_subent == NULL) return NITROARC_ENULL; + const uint8_t nlen = *p_subent & FNTB_DIRENT_MASKSIZE; + for (uint8_t j = 0; j < nlen && size > 1; j++, size--) { + *p_buf++ = *++p_subent; + } + *p_buf++ = '/'; + + uint16_t dirid = leu16(++p_subent) & FNTB_FILESYS_MASKID; + p_dirtab = p_fntb + (FNTB_DIRTAB_ENTRYSIZE * dirid); + p_enttab = p_fntb + leu32(p_dirtab); + i_firstf = leu16(&p_dirtab[4]); + goto loopback; +} + +#undef skip_f +#undef skip_d + +#include "nitroarc.h" + +#include +#include + + +int nitroarc_pinit( + nitroarc_packer_t *p, + uint16_t nfiles, + unsigned named, + unsigned stripped +) { + assert(p); + assert(p->malloc); + assert(p->realloc); + assert(p->free); + assert(nfiles > 0); + + if (nfiles > NARC_MAXFILES) return NITROARC_ETOOMANYFILES; + + p->flags = 0; + p->fimg_capacity = nfiles * 1024; + p->fimg_size = 0; + p->fimg_data = p->malloc(p->ctx, p->fimg_capacity, 1); + p->f_capacity = nfiles; + p->f_count = 0; + p->f_records = p->malloc(p->ctx, nfiles, sizeof(*p->f_records)); + + if (p->fimg_data == NULL) goto erralloc; + if (p->f_records == NULL) goto erralloc; + if (named) p->flags |= PACKCTL_NAMED; + if (stripped) p->flags |= PACKCTL_STRIPPED; + + return NITROARC_ESUCCESS; + +erralloc: + p->free(p->ctx, p->fimg_data, p->fimg_capacity, 1); + p->free(p->ctx, p->f_records, nfiles, sizeof(*p->f_records)); + return NITROARC_EALLOCFAIL; +} + + +#include "nitroarc.h" + +#include +#include +#include + + +int nitroarc_ppack(nitroarc_packer_t *p, void *data, uint32_t size, char *name) { + assert(p); + assert(p->malloc); + assert(p->realloc); + assert(p->free); + + if (!data || size == 0) { + p->f_records[p->f_count] = (nitroarc_file_t){ + .name = name, + .offset = p->fimg_size, + .size = 0, + }; + p->f_count++; + return NITROARC_ESUCCESS; + } + + uint32_t align = align_u(size); + + if ((size_t)(p->fimg_size + size + align) >= (size_t)p->fimg_capacity) { + size_t cap = p->fimg_capacity; + while (p->fimg_size + size + align > cap) cap *= 2; + + if (cap > UINT32_MAX) return NITROARC_ESIZEOVERFLOW; + + void *tmp = p->realloc(p->ctx, p->fimg_data, (uint32_t)cap, 1); + if (tmp == NULL) return NITROARC_EALLOCFAIL; + + p->fimg_data = tmp; + p->fimg_capacity = (uint32_t)cap; + } + + if (PACKCTL_ISNAMED(p)) { + if (name == NULL) return NITROARC_EINVALIDPATH; + + for (const char *p = name; p && *p; p++) { + switch (*p & 0xFF) { + default: break; + + case '\\': + case '?': + case '"': + case '<': + case '>': + case '*': + case ':': + case ';': + case '|': + return NITROARC_EINVALIDPATH; + } + } + } + + uint8_t *fimg_src = data; + uint8_t *fimg_dst = (uint8_t *)p->fimg_data + p->fimg_size; + for (size_t i = 0; i < size; i++) fimg_dst[i] = fimg_src[i]; + for (size_t i = 0; i < align; i++) fimg_dst[size + i] = 0xFF; + + p->f_records[p->f_count] = (nitroarc_file_t){ + .name = name, + .offset = p->fimg_size, + .size = size, + }; + + p->fimg_size += size + align; + p->f_count++; + + return NITROARC_ESUCCESS; +} + + +#include "nitroarc.h" + +#include +#include +#include +#include // only for qsort + + +static const char fntb_unnamed[] = { + 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, +}; + +typedef struct sect sect_t; +struct sect { + uint32_t offs; + uint32_t head; + uint32_t size; +}; + +#define NARC_HEADER (sect_t){ \ + .offs = 0, \ + .head = NARC_HEADERSIZE, \ + .size = 0, \ +} + +#define sect(prev, head_size, data_size) (sect_t){ \ + .offs = prev.offs + prev.head + prev.size, \ + .head = head_size, \ + .size = data_size, \ +} + +#define sectsize(sect) (sect.head + sect.size) + +static uint32_t pack_fntb(nitroarc_packer_t *p, uint8_t **out_dirtab); + +static int pack(nitroarc_packer_t *p, uint8_t *dirtab, uint32_t dirtab_size, uint8_t **out_buf, uint32_t *out_size); +static int pack_stripped(nitroarc_packer_t *p, uint8_t *dirtab, uint32_t dirtab_size, uint8_t **out_buf, uint32_t *out_size); + +static void put_narc(void *base, uint32_t size); +static void put_fatb(void *base, uint32_t size, const nitroarc_packer_t *p); +static void put_fntb(void *base, uint32_t size, const void *_fntb); +static void put_fimg(void *base, uint32_t size, const void *_fimg); + +int nitroarc_pseal(nitroarc_packer_t *p, void **out_data, uint32_t *out_size) { + assert(p); + assert(p->malloc); + assert(p->realloc); + assert(p->free); + assert(out_data); + assert(out_size); + + int errc = NITROARC_ESUCCESS; + uint8_t *dirtab = NULL; + uint32_t dirtab_size = pack_fntb(p, &dirtab); + if (dirtab == NULL) { errc = dirtab_size; goto cleanup; } + + uint32_t size = 0; + uint8_t *data = NULL; + errc = PACKCTL_ISSTRIPPED(p) + ? pack_stripped(p, dirtab, dirtab_size, &data, &size) + : pack(p, dirtab, dirtab_size, &data, &size); + + if (errc) goto cleanup; + + *out_data = data; + *out_size = size; + +cleanup: + p->free(p->ctx, p->fimg_data, p->fimg_size, 1); + p->free(p->ctx, p->f_records, p->f_count, sizeof(*p->f_records)); + if (PACKCTL_ISNAMED(p)) p->free(p->ctx, dirtab, dirtab_size, 1); + return errc; +} + +static int pack(nitroarc_packer_t *p, uint8_t *dirtab, uint32_t dirtab_size, uint8_t **out_buf, uint32_t *out_size) { + sect_t narc = NARC_HEADER; + sect_t fatb = sect(narc, FATB_HEADERSIZE, p->f_capacity * FATB_ENTRYSIZE); + sect_t fntb = sect(fatb, FNTB_HEADERSIZE, dirtab_size); + sect_t fimg = sect(fntb, FIMG_HEADERSIZE, p->fimg_size); + + size_t size = sectsize(narc) + + sectsize(fatb) + + sectsize(fntb) + + sectsize(fimg); + if (size >= UINT32_MAX) return NITROARC_ESIZEOVERFLOW; + + uint32_t usize = (uint32_t)size; + uint8_t *data = p->malloc(p->ctx, usize, 1); + if (data == NULL) return NITROARC_EALLOCFAIL; + + put_narc(data + narc.offs, usize); + put_fatb(data + fatb.offs, fatb.size, p); + put_fntb(data + fntb.offs, fntb.size, dirtab); + put_fimg(data + fimg.offs, fimg.size, p->fimg_data); + + *out_buf = data; + *out_size = usize; + return NITROARC_ESUCCESS; +} + +static int pack_stripped(nitroarc_packer_t *p, uint8_t *dirtab, uint32_t dirtab_size, uint8_t **out_buf, uint32_t *out_size) { + uint32_t head_size = 0x10; + uint32_t fntb_align = align_u32(head_size + dirtab_size); + uint32_t fntb_offs = head_size; + uint32_t fntb_size = dirtab_size + fntb_align; + uint32_t fatb_offs = head_size + fntb_size; + uint32_t fatb_size = p->f_capacity * FATB_ENTRYSIZE; + uint32_t fatb_align = align_u32(fatb_offs + fatb_size); + uint32_t fimg_offs = fatb_offs + fatb_size + fatb_align; + + size_t size = fimg_offs + p->fimg_size; + if (size >= UINT32_MAX) return NITROARC_ESIZEOVERFLOW; + + uint32_t usize = (uint32_t)size; + uint8_t *data = p->malloc(p->ctx, usize, 1); + if (data == NULL) return NITROARC_EALLOCFAIL; + + putleu32(&data[0x00], fntb_offs); + putleu32(&data[0x04], dirtab_size); + putleu32(&data[0x08], fatb_offs); + putleu32(&data[0x0C], fatb_size); + + uint8_t *fntb = &data[fntb_offs]; + uint8_t *fatb = &data[fatb_offs]; + uint8_t *fimg = &data[fimg_offs]; + + for (size_t i = 0; i < dirtab_size; i++) fntb[i] = dirtab[i]; + for (size_t i = dirtab_size; i < fntb_size; i++) fntb[i] = 0; + + for (size_t i = fatb_size; i < fatb_align; i++) fatb[i] = 0; + for (size_t i = 0; i < p->f_count; i++) { + nitroarc_file_t *p_file = &p->f_records[i]; + unsigned char *p_entry = &fatb[i * FATB_ENTRYSIZE]; + + putleu32(&p_entry[0x00], p_file->offset + fimg_offs); + putleu32(&p_entry[0x04], p_file->offset + fimg_offs + p_file->size); + } + + for (size_t i = 0; i < p->fimg_size; i++) { + fimg[i] = ((uint8_t *)p->fimg_data)[i]; + } + + *out_buf = data; + *out_size = usize; + return NITROARC_ESUCCESS; +} + +static void put_narc(void *base, uint32_t size) { + unsigned char *data = (unsigned char *)base; + + putleu32(&data[0x00], SIGNATURE_NARC); + putleu16(&data[0x04], BOM_LITEND); + putleu16(&data[0x06], NARC_VERSION); + putleu32(&data[0x08], size); + putleu16(&data[0x0C], NARC_HEADERSIZE); + putleu16(&data[0x0E], NARC_SECTIONS); +} + +static void put_fatb(void *base, uint32_t size, const nitroarc_packer_t *p) { + unsigned char *head = (unsigned char *)base; + unsigned char *data = head + FATB_HEADERSIZE; + + putleu32(&head[0x00], SIGNATURE_BTAF); + putleu32(&head[0x04], size + FATB_HEADERSIZE); + putleu16(&head[0x08], p->f_count); + putleu16(&head[0x0A], 0); + + for (size_t i = 0; i < p->f_count; i++) { + nitroarc_file_t *p_file = &p->f_records[i]; + unsigned char *p_entry = &data[i * FATB_ENTRYSIZE]; + + putleu32(&p_entry[0x00], p_file->offset); + putleu32(&p_entry[0x04], p_file->offset + p_file->size); + } +} + +static void put_fntb(void *base, uint32_t size, const void *_fntb) { + unsigned char *head = (unsigned char *)base; + unsigned char *data = head + FNTB_HEADERSIZE; + unsigned char *fntb = (unsigned char *)_fntb; + + putleu32(&head[0x00], SIGNATURE_BTNF); + putleu32(&head[0x04], size + FNTB_HEADERSIZE); + + for (size_t i = 0; i < size; i++) data[i] = fntb[i]; +} + +static void put_fimg(void *base, uint32_t size, const void *_fimg) { + unsigned char *head = (unsigned char *)base; + unsigned char *data = head + FIMG_HEADERSIZE; + unsigned char *fimg = (unsigned char *)_fimg; + + putleu32(&head[0x00], SIGNATURE_GMIF); + putleu32(&head[0x04], size + FIMG_HEADERSIZE); + + for (size_t i = 0; i < size; i++) data[i] = fimg[i]; +} + +// ============================ FNTB PACKING CODE =========================== // + +typedef struct fsnode fsnode_t; +struct fsnode { + char *name; + fsnode_t *children; + + uint16_t id; + uint16_t parent; + uint16_t n_children; + uint16_t c_children; + uint16_t first; + uint8_t name_len; +}; + +static int filecmp(const void *lhs, const void *rhs); +static void flatten(fsnode_t *parent, fsnode_t **out); +static unsigned calcenttab(fsnode_t **dirs, uint16_t ndirs, uint16_t nfiles); +static void serialize(fsnode_t **dirs, char *dirtab, char *enttab); + +static int fs_push(nitroarc_packer_t *p, fsnode_t *root, char *path, uint16_t *did, uint16_t *fid); +static void fs_free(nitroarc_packer_t *p, fsnode_t *parent); + +#define INIT_CAP 32 + +static uint32_t pack_fntb(nitroarc_packer_t *p, uint8_t **out_fntb) { + if (!PACKCTL_ISNAMED(p)) { + *out_fntb = (uint8_t *)fntb_unnamed; + return sizeof(fntb_unnamed); + } + + *out_fntb = NULL; + uint16_t dir_id = 0xF000; + uint16_t n_files = 0; + fsnode_t root = { + .name = "", + .children = p->malloc(p->ctx, INIT_CAP, sizeof(fsnode_t)), + .id = dir_id++, + .parent = 0, + .first = n_files, + .n_children = 0, + .c_children = INIT_CAP, + .name_len = 0, + }; + + qsort(p->f_records, p->f_count, sizeof(nitroarc_file_t), filecmp); + + fsnode_t **dirs = NULL; + char *fntb = NULL; + unsigned size = 0; + int errc = NITROARC_ESUCCESS; + + for (size_t i = 0; i < p->f_count; i++) { + errc = fs_push(p, &root, p->f_records[i].name, &dir_id, &n_files); + if (errc) goto erralloc; + } + + root.parent = (dir_id & FNTB_FILESYS_MASKID); + dirs = p->malloc(p->ctx, root.parent, sizeof(fsnode_t*)); + + if (dirs == NULL) { errc = NITROARC_EALLOCFAIL; goto erralloc; } + flatten(&root, dirs); + + unsigned size_dirtab = root.parent * FNTB_DIRTAB_ENTRYSIZE; + unsigned size_enttab = calcenttab(dirs, root.parent, n_files); + + size = size_dirtab + size_enttab; + fntb = p->malloc(p->ctx, size, 1); + char *dirtab = fntb; + char *enttab = fntb + size_dirtab; + + serialize(dirs, dirtab, enttab); + + *out_fntb = (uint8_t *)fntb; + errc = size; + goto cleanup; + +erralloc: + p->free(p->ctx, fntb, size, 1); + +cleanup: + p->free(p->ctx, dirs, root.parent, sizeof(fsnode_t*)); + fs_free(p, &root); + return errc; +} + +static char lower(char c) { + return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; +} + +static int filecmp(const void *_lhs, const void *_rhs) { + const nitroarc_file_t *file_l = _lhs; + const nitroarc_file_t *file_r = _rhs; + + const char *lhs = file_l->name; + const char *rhs = file_r->name; + + int result = 0; + for (; result == 0 && *lhs && *rhs; lhs++, rhs++) { + const char *sep_l = strchrnul(lhs, '/'); + const char *sep_r = strchrnul(rhs, '/'); + + // always sort directories after files + if (*sep_l == '/' && *sep_r != '/') return 1; + if (*sep_l != '/' && *sep_r == '/') return -1; + + for (; result == 0 && lhs != sep_l && rhs != sep_r; lhs++, rhs++) { + result = lower(*lhs) - lower(*rhs); + } + + if (result) return result; + if (lhs != sep_l) return 1; // rhs is shorter + if (rhs != sep_r) return -1; // lhs is shorter + } + + return result; +} + +static void flatten(fsnode_t *parent, fsnode_t **out) { + uint16_t id = parent->id & 0x0FFF; + out[id] = parent; + + for (size_t i = 0; i < parent->n_children; i++) { + fsnode_t *child = &parent->children[i]; + if (child->id >= 0xF000) flatten(child, out); + } +} + +static unsigned calcenttab(fsnode_t **dirs, uint16_t ndirs, uint16_t nfiles) { + unsigned total = 0; + for (int i = 0; i < ndirs; i++) { + total += dirs[i]->name_len; + + for (int j = 0; j < dirs[i]->n_children; j++) { + if (dirs[i]->children[j].children == NULL) { + total += dirs[i]->children[j].name_len; + } + } + } + + return total // Total length of all unique components + + ((ndirs - 1) * 2) // 2 bytes for each subdirectory ID + + (ndirs - 1) // 1 byte for each subdirectory's name-length + + nfiles // 1 byte for each file's name-length + + ndirs; // 1 byte to zero-terminate each entry +} + +static void record(fsnode_t *dir, char *p_dirtab, uint32_t offset) { + putleu32(&p_dirtab[0], offset); + putleu16(&p_dirtab[4], dir->first); + putleu16(&p_dirtab[6], dir->parent); +} + +static void serialize(fsnode_t **dirs, char *dirtab, char *enttab) { + assert(dirs); + assert(dirs[0]); + + uint16_t n_dirs = dirs[0]->parent; + char *p_dirtab = dirtab; + char *p_enttab = enttab; + + for (int i = 0; i < n_dirs; i++) { + fsnode_t *dir = dirs[i]; + record(dir, p_dirtab, (uint32_t)(p_enttab - dirtab)); + + for (int j = 0; j < dir->n_children; j++) { + fsnode_t *child = &dir->children[j]; + *p_enttab++ = child->name_len | ((child->id >= 0xF000) * FNTB_DIRENT_MASKTYPE); + + for (int k = 0; k < child->name_len; k++) { + *p_enttab++ = child->name[k]; + } + + if (child->id >= 0xF000) { + putleu16(p_enttab, child->id); + p_enttab += 2; + } + } + + *p_enttab = 0; + p_dirtab += FNTB_DIRTAB_ENTRYSIZE; + p_enttab += 1; + } +} + +static void fs_free(nitroarc_packer_t *p, fsnode_t *parent) { + for (size_t i = 0; i < parent->n_children; i++) { + fs_free(p, &parent->children[i]); + } + + p->free(p->ctx, parent->children, parent->n_children, sizeof(fsnode_t)); +} + +static int fs_pushone( + nitroarc_packer_t *p, + fsnode_t *parent, + char *path, + uint8_t path_len, + uint16_t *id, + uint16_t first, + fsnode_t **out_child +) { + assert(parent); + assert(path); + assert(id); + assert(out_child); + + *out_child = NULL; + + for (size_t i = 0; i < parent->n_children; i++) { + fsnode_t *child = &parent->children[i]; + + char *p = path; + char *s = child->name; + for (; *p && *s && *p == *s; p++, s++); + + if (*p == *s) { + *out_child = child; + return NITROARC_ESUCCESS; + } + } + + // no match found; add this as a child + if (parent->n_children + 1 >= parent->c_children) { + int cap = parent->c_children * 2; + if (cap > UINT16_MAX) return NITROARC_EALLOCFAIL; + + fsnode_t *tmp = p->realloc(p->ctx, parent->children, cap, sizeof(fsnode_t)); + if (tmp == NULL) return NITROARC_EALLOCFAIL; + + parent->c_children = (uint16_t)cap; + parent->children = tmp; + } + + fsnode_t *child = &parent->children[parent->n_children++]; + child->name = path; + child->children = NULL; + child->id = *id; + child->parent = parent->id; + child->first = first; + child->n_children = 0; + child->c_children = 0; + child->name_len = path_len; + + if (*id >= 0xF000) { + child->c_children = INIT_CAP; + child->children = p->malloc(p->ctx, INIT_CAP, sizeof(fsnode_t)); + if (child->children == NULL) return NITROARC_EALLOCFAIL; + } + + (*id)++; + *out_child = child; + return NITROARC_ESUCCESS; +} + +static int fs_push( + nitroarc_packer_t *p, + fsnode_t *root, + char *path, + uint16_t *did, + uint16_t *fid +) { + int errc = NITROARC_ESUCCESS; + fsnode_t *child = NULL; + + char *s; + for (s = path; s && *s; s++) { + if (*s == '/') { + *s = 0; + errc = fs_pushone(p, root, path, (uint8_t)(s - path), did, *fid, &child); + if (errc) return errc; + + path = s + 1; + root = child; + } + } + + errc = fs_pushone(p, root, path, (uint8_t)(s - path), fid, 0, &child); + if (errc) return errc; + + return NITROARC_ESUCCESS; +} + + +#include +#include + + +// Minimum allowable size for a standard NARC file: no member files +// +12 is the minimum size of an FNTB data section: +// - 8 bytes for the root directory entry +// - 1 byte for the subdirectory entry terminator +// - 3 bytes of alignment padding +#define NARC_MINSIZE ( \ + NARC_HEADERSIZE \ + + FATB_HEADERSIZE \ + + FNTB_HEADERSIZE \ + + FIMG_HEADERSIZE \ + + 12 \ +) + +static int nitroarc_fatb(nitroarc_t *narc, int64_t *running_size); +static int nitroarc_fntb(nitroarc_t *narc, int64_t *running_size); +static int nitroarc_fimg(nitroarc_t *narc, int64_t *running_size); + +static int read_stripped(const uint8_t *blob, uint32_t size, nitroarc_t *narc); + +int nitroarc_read(const void *blob, uint32_t size, nitroarc_t *narc) { + if (narc == NULL) return NITROARC_ENULL; + if (blob == NULL) return NITROARC_ENULL; + if (size < NARC_MINSIZE) return NITROARC_ESIZERANGE; + *narc = (nitroarc_t){ 0 }; + + const uint8_t *data = blob; + if (leu32(&data[0x00]) != SIGNATURE_NARC) return read_stripped(data, size, narc); + if (leu16(&data[0x04]) != BOM_LITEND) return NITROARC_EBYTEORDER; + if (leu16(&data[0x06]) != NARC_VERSION) return NITROARC_EVERSION; + if (leu32(&data[0x08]) != size) return NITROARC_EARCHIVESIZE; + if (leu16(&data[0x0C]) != NARC_HEADERSIZE) return NITROARC_EHEADERSIZE; + if (leu16(&data[0x0E]) != NARC_SECTIONS) return NITROARC_ESECTIONS; + + narc->size = (uint32_t)size; + narc->head = data; + narc->fatb.data = data + NARC_HEADERSIZE; // Start of section + + // Safety: make sure the section sizes are sensible along the way + int64_t running_size = size - NARC_HEADERSIZE; + int errc = nitroarc_fatb(narc, &running_size) + || nitroarc_fntb(narc, &running_size) + || nitroarc_fimg(narc, &running_size) + || NITROARC_ESUCCESS; + + if (errc) *narc = (nitroarc_t){ 0 }; + return errc; +} + +static int nitroarc_fatb(nitroarc_t *narc, int64_t *running_size) { + const uint8_t *head = narc->fatb.data; + + if (leu32(&head[0x00]) != SIGNATURE_BTAF) return NITROARC_EFATBSIG; + + uint32_t size = leu32(&head[0x04]); + *running_size -= size; + if (*running_size < 0) return NITROARC_EFATBSIZE; + + uint16_t nfiles = leu16(&head[0x08]); + uint32_t xsize = (uint32_t)(FATB_HEADERSIZE + (nfiles * FATB_ENTRYSIZE)); + if (size != xsize) return NITROARC_ENUMFILES; + + narc->fatb.size = size; + narc->fatb.data = head + FATB_HEADERSIZE; // First entry pointer + narc->fntb.data = head + narc->fatb.size; // Head of next section + narc->fatb.ofs_head = (uint32_t)ptrdiff(head, narc->head); + narc->fatb.ofs_data = (uint32_t)ptrdiff(narc->fatb.data, narc->head); + + narc->nfiles = nfiles; + return NITROARC_ESUCCESS; +} + +static int nitroarc_fntb(nitroarc_t *narc, int64_t *running_size) { + const uint8_t *head = narc->fntb.data; + + if (leu32(&head[0x00]) != SIGNATURE_BTNF) return NITROARC_EFNTBSIG; + + uint32_t size = leu32(&head[0x04]); + *running_size -= size; + if (*running_size < 0) return NITROARC_EFNTBSIZE; + + narc->fntb.size = size; + narc->fntb.data = head + FNTB_HEADERSIZE; // First entry pointer + narc->fimg.data = head + narc->fntb.size; // Head of next section + narc->fntb.ofs_head = (uint32_t)ptrdiff(head, narc->head); + narc->fntb.ofs_data = (uint32_t)ptrdiff(narc->fntb.data, narc->head); + + narc->ndirs = leu16(&((uint8_t *)narc->fntb.data)[0x06]); + return NITROARC_ESUCCESS; +} + +static int nitroarc_fimg(nitroarc_t *narc, int64_t *running_size) { + const char *head = narc->fimg.data; + if (leu32(&head[0x00]) != SIGNATURE_GMIF) return NITROARC_EFIMGSIG; + + uint32_t size = leu32(&head[0x04]); + *running_size -= size; + if (*running_size < 0) return NITROARC_EFIMGSIZE; + + narc->fimg.size = size; + narc->fimg.data = head + FIMG_HEADERSIZE; // First entry pointer + narc->fimg.ofs_head = (uint32_t)ptrdiff(head, narc->head); + narc->fimg.ofs_data = (uint32_t)ptrdiff(narc->fimg.data, narc->head); + + return NITROARC_ESUCCESS; +} + +static int read_stripped(const uint8_t *data, uint32_t size, nitroarc_t *narc) { + if (size < 0x10) return NITROARC_ESIGNATURE; + + const uint32_t fntb_offs = leu32(&data[0x00]); + const uint32_t fatb_offs = leu32(&data[0x08]); + const uint32_t fntb_size = leu32(&data[0x04]); + const uint32_t fatb_size = leu32(&data[0x0C]); + + uint32_t expected = fntb_offs + fntb_size + align_u32(fntb_offs + fntb_size); + if (fntb_offs != 0x10 || fatb_offs != expected) { + return NITROARC_ESIGNATURE; + } + + narc->size = size; + narc->head = data; + + narc->fatb.size = fatb_size; + narc->fatb.data = data + fatb_offs; + narc->fatb.ofs_head = 0x08; + narc->fatb.ofs_data = fatb_offs; + narc->nfiles = (uint16_t)(fatb_size / FATB_ENTRYSIZE); + + narc->fntb.size = fntb_size; + narc->fntb.data = data + fntb_offs; + narc->fntb.ofs_head = 0x00; + narc->fntb.ofs_data = fntb_offs; + narc->ndirs = leu16(&((uint8_t *)narc->fntb.data)[0x06]); + + narc->fimg.size = size - fntb_size - fatb_size - 0x10; + narc->fimg.data = data; // all FATB offsets in stripped variant are absolute + narc->fimg.ofs_head = 0x00; + narc->fimg.ofs_data = 0x00; + + return NITROARC_ESUCCESS; +} diff --git a/tools/nitroarc/meson.build b/tools/nitroarc/meson.build new file mode 100644 index 0000000000..ec3518d63e --- /dev/null +++ b/tools/nitroarc/meson.build @@ -0,0 +1,45 @@ +nitroarc_cflags = [ + '-std=c99', + '-DNDEBUG', + '-O3', + '-Wall', + '-Wextra', + '-Wpedantic', + '-Wconversion', + '-Wno-sign-conversion', + '-Werror', +] + +nitroarc_incdir = include_directories('lib/include') + +nitroarc_dep = declare_dependency( + include_directories: nitroarc_incdir, + link_with: static_library( + 'nitroarc', + sources: files('lib/nitroarc.c'), + + c_args: nitroarc_cflags, + include_directories: nitroarc_incdir, + install: false, + native: true, + ), +) + +nitroarc_exe = executable( + 'nitroarc', + sources: files( + 'src/common.c', + 'src/extensions.c', + 'src/main.c', + 'src/opmode_create.c', + 'src/opmode_extract.c', + 'src/opmode_list.c', + 'src/opmode_metadata.c', + 'src/optparse.c', + ), + + c_args: nitroarc_cflags, + dependencies: nitroarc_dep, + install: false, + native: true, +) diff --git a/tools/nitroarc/src/common.c b/tools/nitroarc/src/common.c new file mode 100644 index 0000000000..99aeed50a5 --- /dev/null +++ b/tools/nitroarc/src/common.c @@ -0,0 +1,184 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nitroarc.h" + +static FILE *s_logfile = NULL; + +void progput(FILE *stream, const char *fmt, va_list args) { + fputs(PROGRAM ": ", stream); + vfprintf(stream, fmt, args); + fputc('\n', stream); +} + +void progerr(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + progput(stderr, fmt, args); + va_end(args); +} + +void proglog(const char *fmt, ...) { + if (s_logfile) { + va_list args; + va_start(args, fmt); + progput(stdout, fmt, args); + va_end(args); + } +} + +int open_file(const char *path, const char *mode, FILE **out_f) { + assert(out_f); + + FILE *f = fopen(path, mode); + if (f == NULL) { + progerr("could not open file '%s': %s", path, strerror(errno)); + return PROGRAM_EFILEIO; + } + + *out_f = f; + return PROGRAM_ENONE; +} + +int load_file(const char *path, char **out_buf, size_t *out_size) { + assert(out_buf); + assert(out_size); + + if (path == NULL) return PROGRAM_ENONE; + + FILE *f = NULL; + char *buf = NULL; + int errc = open_file(path, "rb", &f); + if (errc) return errc; + if (!f) return PROGRAM_EGENERAL; // NOTE: Only to silence the compiler + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + if (fsize == 0) { fclose(f); return PROGRAM_ENONE; } + if (fsize < 0) { + progerr("negative size for file '%s': %s", path, strerror(errno)); + errc = PROGRAM_EFILEIO; + goto cleanup; + } + + if ((buf = calloc(fsize + 1, 1)) == NULL) { + progerr("alloc failure for file '%s': %s", path, strerror(errno)); + errc = PROGRAM_EALLOC; + goto cleanup; + } + + long nread = fread(buf, 1, fsize, f); + if (nread != fsize) { + progerr("I/O failure for file '%s': %s", path, strerror(errno)); + errc = PROGRAM_EFILEIO; + goto cleanup; + } + + *out_buf = buf; + *out_size = fsize; + fclose(f); + return PROGRAM_ENONE; + +cleanup: + free(buf); + fclose(f); + return errc; +} + +int read_archive(const char *data, size_t size, nitroarc_t *narc) { + assert(data); + assert(narc); + + if (size > UINT32_MAX) { + progerr("input data is too large to be an archive"); + return PROGRAM_EGENERAL; + } + + int errc = nitroarc_read(data, (uint32_t)size, narc); + if (errc) { + progerr("archive format error: %s", nitroarc_errs(errc)); + return PROGRAM_ELIBERROR; + } + + return PROGRAM_ENONE; +} + +int set_logfile(bool verbose) { + s_logfile = verbose ? stderr : NULL; + return PROGRAM_ENONE; +} + +int ensure_mkdir(const char *path) { + if (path == NULL || path[0] == 0) return PROGRAM_ENONE; + + if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) { + if (errno != EEXIST) { + progerr("could not create directory '%s': %s", path, strerror(errno)); + return PROGRAM_EGENERAL; + } + + errno = 0; + } else { + proglog("created new directory '%s'", path); + } + + return PROGRAM_ENONE; +} + +int set_workdir(const char *path) { + int errc = ensure_mkdir(path); + if (errc) return errc; + + if (path && chdir(path) == -1) { + progerr("could not change directory '%s': %s", path, strerror(errno)); + return PROGRAM_EFILEIO; + } + + return PROGRAM_ENONE; +} + +int write_file(const char *path, void *data, size_t size) { + assert(data); + + FILE *f = NULL; + int errc = open_file(path, "wb", &f); + if (errc) return errc; + if (!f) return PROGRAM_EGENERAL; // NOTE: Only to silence the compiler + + if (fwrite(data, 1, size, f) != size) { + progerr("partial write failure for file '%s': %s", path, strerror(errno)); + return PROGRAM_EFILEIO; + } + + fclose(f); + return PROGRAM_ENONE; +} diff --git a/tools/nitroarc/src/common.h b/tools/nitroarc/src/common.h new file mode 100644 index 0000000000..af0c21d03b --- /dev/null +++ b/tools/nitroarc/src/common.h @@ -0,0 +1,79 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef TOOL_COMMON_H +#define TOOL_COMMON_H + +#include +#include +#include + +#include "nitroarc.h" + +#ifdef __GNUC__ +# define ATTR_FORMAT(f, a) __attribute__((format(printf, f, a))) +#else +# define ATTR_FORMAT(f, a) +#endif + +#define PROGRAM "nitroarc" +#define PROGRAM_NOFILE "no archive file specified (missing -f option?)" +#define PROGRAM_HELP "try '%s --help' for more information" + +#define PROGRAM_ENONE 0 +#define PROGRAM_EGENERAL 1 +#define PROGRAM_EFILEIO 2 +#define PROGRAM_EALLOC 3 +#define PROGRAM_ELIBERROR 127 + +typedef struct options options_t; +struct options { + unsigned int mode : 4; // operation mode + unsigned int verbose : 1; // -v, --verbose + unsigned int help : 1; // -?, --help + unsigned int version : 1; // --version + unsigned int no_header : 1; // --no-header + unsigned int index : 1; // -N, --index + unsigned int no_recurse : 1; // --no-recursion + unsigned int named : 1; // --named + unsigned int stripped : 1; // --stripped + + int argc; + const char **argv; + const char *name; + + const char *directory; // -C, --directory=DIR + const char *file; // -f, --file=ARCHIVE + const char *format; // -F, --format=FORMAT + const char *files_from; // -T, --files-from=FILE + const char *exclude_from; // -X, --exclude-from=FILE + const char *exclude_pat; // --exclude=PATTERN +}; + +ATTR_FORMAT(1, 2) void progerr(const char *fmt, ...); +ATTR_FORMAT(1, 2) void proglog(const char *fmt, ...); + +int open_file(const char *path, const char *mode, FILE **out_f); +int load_file(const char *path, char **out_buf, size_t *out_size); +int write_file(const char *path, void *data, size_t size); +int read_archive(const char *data, size_t size, nitroarc_t *narc); +int set_logfile(bool verbose); +int set_workdir(const char *path); +int ensure_mkdir(const char *path); + +#endif // TOOL_COMMON_H diff --git a/tools/nitroarc/src/extensions.c b/tools/nitroarc/src/extensions.c new file mode 100644 index 0000000000..809b45932d --- /dev/null +++ b/tools/nitroarc/src/extensions.c @@ -0,0 +1,56 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "extensions.h" + +#include +#include + +const extension_t extensions[] = { + { "RGCN", "NCGR", 4 }, + { "RLCN", "NCLR", 4 }, + { "RECN", "NCER", 4 }, + { "RNAN", "NANR", 4 }, + { "RCSN", "NSCR", 4 }, + { "BMD0", "BMD0", 4 }, + { "BCA0", "BCA0", 4 }, + { "BTA0", "BTA0", 4 }, + { "BTP0", "BTP0", 4 }, + { "BTX0", "BTX0", 4 }, + { "BMA0", "BMA0", 4 }, + { "BVA0", "BVA0", 4 }, + { " APS", "spa", 4 }, + + { NULL, "bin", 0 }, // fallback; must ALWAYS be last! +}; + +const extension_t* guess_extension(const void *_data) { + assert(_data); + const unsigned char *data = _data; + + if (data[0] == 0x10 && data[4] == 0x00) { + // This should be an LZ77-encoded file; the first block of such an + // encoding is always stored in full, which means we should see the + // extension starting at index 5. + return guess_extension(data + 5); + } + + const extension_t *c = &extensions[0]; + while (c->magic != NULL && memcmp(data, c->magic, c->size) != 0) c++; + return c; +} diff --git a/tools/nitroarc/src/extensions.h b/tools/nitroarc/src/extensions.h new file mode 100644 index 0000000000..3e1bb3f3e1 --- /dev/null +++ b/tools/nitroarc/src/extensions.h @@ -0,0 +1,35 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef TOOL_EXTENSIONS_H +#define TOOL_EXTENSIONS_H + +#include + +typedef struct extension extension_t; +struct extension { + const char *magic; + const char *ext; + size_t size; +}; + +extern const extension_t extensions[]; + +const extension_t* guess_extension(const void *data); + +#endif // TOOL_EXTENSIONS_H diff --git a/tools/nitroarc/src/main.c b/tools/nitroarc/src/main.c new file mode 100644 index 0000000000..8f9a6fc220 --- /dev/null +++ b/tools/nitroarc/src/main.c @@ -0,0 +1,252 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "common.h" +#include "optparse.h" + +enum { + opmode_none = 0, + opmode_metadata, + opmode_list, + opmode_extract, + opmode_create, + + opmode_max, +}; + +static int (*opmode_funcs[opmode_max])(const options_t *opts); +static void exit_help(const char *name, int exit_status); +static void exit_version(void); +static int parse_opts(const char **argv, options_t *opts); + +int main(int argc, const char **argv) { + options_t opts = { 0 }; + opts.name = argv[0]; + opts.argc = argc - parse_opts(argv, &opts); + opts.argv = argv + (argc - opts.argc); + + assert(opts.mode < opmode_max); + assert(opmode_funcs[opts.mode] != NULL); + + if (opts.mode == opmode_none) { + progerr("no operation mode specified"); + progerr(PROGRAM_HELP, opts.name); + exit(EXIT_FAILURE); + } + + int errc = set_logfile(opts.verbose) + || set_workdir(opts.directory) + || opmode_funcs[opts.mode](&opts); + + exit(errc); +} + +extern int tool_metadata(const options_t *opts); +extern int tool_list(const options_t *opts); +extern int tool_extract(const options_t *opts); +extern int tool_create(const options_t *opts); + +static int (*opmode_funcs[opmode_max])(const options_t *opts) = { + [opmode_none] = NULL, + [opmode_metadata] = tool_metadata, + [opmode_list] = tool_list, + [opmode_extract] = tool_extract, + [opmode_create] = tool_create, +}; + +enum { + metadata = 0, + list, + extract, + create, + + directory, + file, + verbose, + + format, + no_header, + + exclude, + exclude_from, + files_from, + index, + no_recurse, + named, + stripped, + + help, + version, +}; + +static const option_cfg_t s_options[] = { + [metadata] = { "metadata", "meta", 'm', 0, false }, + [list] = { "list", NULL, 't', 0, false }, + [extract] = { "extract", NULL, 'x', 0, false }, + [create] = { "create", NULL, 'c', 0, false }, + + [directory] = { "directory", NULL, 'C', 0, true }, + [file] = { "file", NULL, 'f', 0, true }, + [verbose] = { "verbose", NULL, 'v', 0, false }, + + [format] = { "format", NULL, 'F', 0, true }, + [no_header] = { "no-header", NULL, 'H', 0, false }, + + [exclude] = { "exclude", NULL, 'E', 0, true }, + [exclude_from] = { "exclude-from", NULL, 'X', 0, true }, + [files_from] = { "files-from", NULL, 'T', 0, true }, + [index] = { "index", NULL, 'I', 0, false }, + [no_recurse] = { "no-recursion", NULL, 'R', 0, false }, + [named] = { "named", NULL, 'N', 0, false }, + [stripped] = { "stripped", NULL, 'S', 0, false }, + + [help] = { "help", NULL, '?', 'h', false }, + [version] = { "version", NULL, 'V', 0, false }, + + { 0 }, +}; + +#define target_optarg(__val) __val = parser.optarg; break +#define tryset_opmode(__mode) \ + if (opts->mode) { \ + progerr("only one operation mode permitted"); \ + progerr(PROGRAM_HELP, opts->name); \ + exit(EXIT_FAILURE); \ + } \ + else { opts->mode = __mode; } \ + break + +int parse_opts(const char **argv, options_t *opts) { + assert(argv); + assert(opts->name); + + if (argv && argv[0] != NULL && argv[1] == NULL) { + exit_help(opts->name, EXIT_FAILURE); + } + + optparser_t parser = { + .argv = (char **)argv, + .optind = 1, + .shortind = 1, + .optarg = NULL, + .errmsg = { 0 }, + .options = s_options, + }; + + int match; + while ((match = parseopt(&parser)) >= 0) { + switch (match) { + case metadata: tryset_opmode(opmode_metadata); + case list: tryset_opmode(opmode_list); + case extract: tryset_opmode(opmode_extract); + case create: tryset_opmode(opmode_create); + + case directory: target_optarg(opts->directory); + case file: target_optarg(opts->file); + case format: target_optarg(opts->format); + case files_from: target_optarg(opts->files_from); + case exclude_from: target_optarg(opts->exclude_from); + case exclude: target_optarg(opts->exclude_pat); + + case verbose: opts->verbose = true; break; + case no_header: opts->no_header = true; break; + case index: opts->index = true; break; + case no_recurse: opts->no_recurse = true; break; + case named: opts->named = true; break; + case stripped: opts->stripped = true; break; + + case OPT_ERROR: + progerr("%s", parser.errmsg); + progerr(PROGRAM_HELP, opts->name); + exit(EXIT_FAILURE); + + case help: exit_help(opts->name, EXIT_SUCCESS); break; + case version: exit_version(); break; + } + } + + return parser.optind; +} + +#define putf printf // Only for nice alignment below + +static void exit_help(const char *name, int exit_status) { + putf("Usage: %s [OPTION]... [ARGS]...\n", name); + puts(""); + puts("An archiving utility for Nintendo's Nitro Archive format."); + puts(""); + puts("Examples:"); + putf(" %s -cf archive.narc # Create archive.narc from files.\n", name); + putf(" %s -mf archive.narc # View metadata for archive.narc.\n", name); + putf(" %s -tf archive.narc # List member files in archive.narc.\n", name); + putf(" %s -xf archive.narc # Extract files from archive.narc.\n", name); + puts(""); + puts("Operation modes:"); + puts(" -c, --create create an archive from member files"); + puts(" -m, --meta, --metadata view tabulated archive metadata"); + puts(" -t, --list view tabulated archive member files"); + puts(" -x, --extract extract archive member files"); + puts(""); + puts("Common options:"); + puts(" -C, --directory=DIR change to directory DIR before operation"); + puts(" -f, --file=ARCHIVE target the file ARCHIVE"); + puts(" -v, --verbose be more talkative during execution"); + puts(""); + puts("Archive creation options:"); + puts(" -E, --exclude=PATTERN exclude filenames matching PATTERN"); + puts(" -X, --exclude-from=FILE read exclusion patterns from FILE"); + puts(" -T, --files-from=FILE read ordered filenames from FILE"); + puts(" -I, --index create a C-header index of member files"); + puts(" -N, --named retain filenames in the archive"); + puts(" -R, --no-recursion do not discover files in subdirectories"); + puts(" -S, --stripped do not write the signed file-type header"); + puts(""); + puts("Tabulated data options:"); + puts(" -F, --format=FORMAT output data in FORMAT (default: markdown)"); + puts(" -H, --no-header do not output header row(s)"); + puts(""); + puts("Program information:"); + puts(" -?, -h, --help output this help text and exit"); + puts(" --version output version information and exit"); + puts(""); + puts("For detailed information on program operation and capabilities, try"); + puts("consulting 'man nitroarc.1', if you have it installed."); + puts(""); + puts("Report bugs and submit patches to ."); + + exit(exit_status); +} + +static void exit_version(void) { + puts("nitroarc v0.0.1"); + puts(""); + puts("Copyright (C) 2026 Rachel "); + puts(""); + puts("License LGPLv3+: GNU LGPL version 3 or later. For full license"); + puts("details, see: "); + puts(""); + puts("This is free software: you are free to change and redistribute it."); + puts("There is NO WARRANTY, to the extent permitted by law."); + + exit(EXIT_SUCCESS); +} diff --git a/tools/nitroarc/src/opmode_create.c b/tools/nitroarc/src/opmode_create.c new file mode 100644 index 0000000000..564895b2b6 --- /dev/null +++ b/tools/nitroarc/src/opmode_create.c @@ -0,0 +1,567 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nitroarc.h" +#include "common.h" + +typedef struct dirent dirent_t; +typedef struct stat stat_t; +typedef struct strvec strvec_t; +typedef struct packcfg packcfg_t; + +struct strvec { + char **data; + size_t size; + size_t cap; +}; + +struct packcfg { + strvec_t files; + bool named; + bool stripped; +}; + +static int prepare_exclusions(const char *fdata, const char *pat, strvec_t *out_excls); +static int collect_explicit_files(const char *fdata, packcfg_t *out_cfg); +static int collect_implicit_files(strvec_t *files, const strvec_t *excls, size_t *out_nexpls); +static int pack_archive(packcfg_t *cfg, void **out_data, size_t *out_size); +static int write_index(const char *fname, bool index, const strvec_t *files); + +extern int tool_create(const options_t *opts) { + if (opts->file == NULL) { + progerr(PROGRAM_NOFILE); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + if (opts->argc == 0) { + progerr("no input directory specified (missing argument?)"); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + stat_t stb = { 0 }; + if (stat(opts->argv[0], &stb) == -1) { + progerr("could not stat input directory: %s", strerror(errno)); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + if (!S_ISDIR(stb.st_mode)) { + progerr("input argument is not a directory"); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + packcfg_t cfg = { + .files = (strvec_t){ 0 }, + .named = opts->named, + .stripped = opts->stripped, + }; + + strvec_t excls = { 0 }; + char *ogcwd = getcwd(NULL, 0); + char *f_incl = NULL; + char *f_excl = NULL; + char *data = NULL; + size_t size = 0; + size_t nexpls = 0; + assert(ogcwd); + + int errc = load_file(opts->files_from, &f_incl, &size) + || load_file(opts->exclude_from, &f_excl, &size) + || set_workdir(opts->argv[0]) + || prepare_exclusions(f_excl, opts->exclude_pat, &excls) + || collect_explicit_files(f_incl, &cfg) + || collect_implicit_files(&cfg.files, &excls, &nexpls) + || pack_archive(&cfg, (void **)&data, &size) + || set_workdir(ogcwd) + || write_file(opts->file, data, size) + || write_index(opts->file, opts->index, &cfg.files) + || EXIT_SUCCESS; + + for (size_t i = nexpls; i < cfg.files.size; i++) free(cfg.files.data[i]); + free(cfg.files.data); + free(excls.data); // none are internally-owned + free(ogcwd); + free(f_incl); + free(f_excl); + free(data); + return errc; +} + +static bool strvec_has(const strvec_t *vec, char *s); +static int strvec_grow(strvec_t *vec); +static int strvec_push(strvec_t *vec, char *s); +static int lexicsort(const void *_lhs, const void *_rhs); + +#define is_hspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r') + +static inline char* strltrim(const void *_s) { + assert(_s); + + const unsigned char *s = _s; + while (s && *s && is_hspace(*s)) s++; + + return (char *)s; +} + +static inline char* strrtrim(const void *_s, const void *_p) { + assert(_s); + assert(_p); + + const unsigned char *s = _s; + const unsigned char *p = _p; + while (p && p != s && *p && is_hspace(*p)) p--; + + return (char *)p; +} + +static inline char* streol(const void *_s) { + assert(_s); + + const unsigned char *s = _s; + while (s && *s && *s != '\n') s++; + + return (char *)s; +} + +static int prepare_exclusions( + const char *fdata, + const char *pat, + strvec_t *out_excls +) { + assert(out_excls); + assert(out_excls->data == NULL); + + out_excls->cap = 64; + out_excls->data = malloc(out_excls->cap * sizeof(*out_excls->data)); + if (out_excls->data == NULL) goto erralloc; + + if (pat != NULL) strvec_push(out_excls, (char *)pat); + if (fdata == NULL) goto done; + + char *s = (char *)fdata; + for (char *p = NULL, *n = NULL; *s; s = n) { + s = strltrim(s); + p = streol(s); + n = *p ? p + 1 : p; + p = strrtrim(s, p - 1); + p[1] = 0; + + if (p == s) continue; + + proglog("f %s", s); + if (strvec_push(out_excls, s)) goto erralloc; + } + +done: + return PROGRAM_ENONE; + +erralloc: + progerr("alloc failure reading ordered inclusions: %s", strerror(errno)); + return PROGRAM_EALLOC; +} + +static int collect_explicit_files(const char *fdata, packcfg_t *cfg) { // bool allow_dupes, strvec_t *out_files) { + assert(cfg); + assert(cfg->files.data == NULL); + + strvec_t *out_files = &cfg->files; + bool allow_dupes = !cfg->named; + int errc = PROGRAM_ENONE; + + out_files->cap = 64; + out_files->data = malloc(out_files->cap * sizeof(*out_files->data)); + if (out_files->data == NULL) goto erralloc; + + if (fdata == NULL) return PROGRAM_ENONE; + + stat_t stb = { 0 }; + char *s = (char *)fdata; + for (char *p = NULL, *n = NULL; *s; s = n) { + s = strltrim(s); + p = streol(s); + n = *p ? p + 1 : p; + p = strrtrim(s, p - 1); + p[1] = 0; + + if (p == s) continue; + if (stat(s, &stb) == -1) goto errstat; + if (S_ISDIR(stb.st_mode)) continue; + + if (!allow_dupes && strvec_has(out_files, s)) continue; + + proglog("f %s", s); + if (strvec_push(out_files, s)) goto erralloc; + } + + return PROGRAM_ENONE; + +erralloc: + progerr("alloc failure reading ordered inclusions: %s", strerror(errno)); + errc = PROGRAM_EALLOC; + goto errcleanup; + +errstat: + progerr("I/O failure statting file '%s': %s", s, strerror(errno)); + errc = PROGRAM_EFILEIO; + goto errcleanup; + +errcleanup: + free(out_files->data); + + *out_files = (strvec_t){ 0 }; + return errc; +} + +static bool should_exclude(const char *name, const strvec_t *excls) { + for (size_t i = 0; i < excls->size; i++) { + if (fnmatch(excls->data[i], name, 0) == 0) return true; + } + + return false; +} + +static char* join_paths(const char *parent, const char *entry) { + size_t size_p = parent ? strlen(parent) + 1 : 0; + size_t size_e = strlen(entry); + + char *path = malloc(size_p + size_e + 1); + if (path != NULL) { + if (size_p) { + memcpy(path, parent, size_p - 1); + path[size_p - 1] = '/'; + } + + memcpy(path + size_p, entry, size_e); + path[size_p + size_e] = 0; + } + + return path; +} + +static int collect_implicit_files(strvec_t *files, const strvec_t *excls, size_t *out_nexpls) { + assert(files); + assert(files->data); + assert(excls); + assert(out_nexpls); + + *out_nexpls = files->size; + DIR *dir = NULL; + int errc = PROGRAM_ENONE; + char *errp = NULL; + + strvec_t queue = { + .data = malloc(64 * sizeof(char *)), + .size = 0, + .cap = 64, + }; + + if (queue.data == NULL) goto erralloc; + strvec_push(&queue, "."); + + for (size_t i = 0; i < queue.size; i++) { + char *path = queue.data[i]; + if ((dir = opendir(path)) == NULL) goto errio; + + // Simplify the check for the root directory + path = path[0] == '.' && path[1] == 0 + ? NULL + : path; + + dirent_t *ent = NULL; + stat_t stb = { 0 }; + while (errno = 0, (ent = readdir(dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0) continue; + if (strcmp(ent->d_name, "..") == 0) continue; + + char *name = join_paths(path, ent->d_name); + if (name == NULL) goto erralloc; + + if (stat(name, &stb) == -1) { errp = name; goto errstat; } + + if (S_ISDIR(stb.st_mode)) { + if (strvec_push(&queue, name)) goto erralloc; + } + else if (strvec_has(files, name)) { free(name); } + else if (should_exclude(name, excls)) { free(name); } + else { + proglog("f %s", name); + if (strvec_push(files, name)) goto erralloc; + } + } + + free(path); + closedir(dir); + } + + // Only sort implicit includes + qsort( + &files->data[*out_nexpls], + files->size - *out_nexpls, + sizeof(*files->data), + lexicsort + ); + + free(queue.data); + return PROGRAM_ENONE; + +erralloc: + progerr("alloc failure walking directory: %s", strerror(errno)); + errc = PROGRAM_EALLOC; + goto errcleanup; + +errio: + progerr("I/O failure walking directory: %s", strerror(errno)); + errc = PROGRAM_EFILEIO; + goto errcleanup; + +errstat: + progerr("I/O failure statting file '%s': %s", errp, strerror(errno)); + errc = PROGRAM_EFILEIO; + free(errp); // NOTE: points to the last-pulled filename + goto errcleanup; + +errcleanup: + if (dir) closedir(dir); + free(queue.data); + return errc; +} + +static void* libc_malloc(void *ctx, unsigned items, unsigned size) { + (void)ctx; + + return malloc(items * size); +} + +static void libc_free(void *ctx, void *ptr, unsigned items, unsigned size) { + (void)ctx; + (void)items; + (void)size; + + free(ptr); +} + +static void* libc_realloc(void *ctx, void *ptr, unsigned items, unsigned size) { + (void)ctx; + + return realloc(ptr, items * size); +} + +static int pack_archive(packcfg_t *cfg, void **out_data, size_t *out_size) { + nitroarc_packer_t packer = { 0 }; + packer.malloc = libc_malloc; + packer.free = libc_free; + packer.realloc = libc_realloc; + + char *data = NULL; + size_t size = 0; + uint32_t usize = 0; + + if (cfg->files.size > UINT16_MAX) { + progerr("too many files to be packed"); + return PROGRAM_EGENERAL; + } + + int errc = nitroarc_pinit( + &packer, + (uint16_t)cfg->files.size, + cfg->named, + cfg->stripped + ); + if (errc) goto errlib; + + for (size_t i = 0; i < cfg->files.size; i++) { + errc = load_file(cfg->files.data[i], &data, &size); + if (errc) goto errcleanup; + if (size > UINT32_MAX) { + progerr("input file '%s' is too large", cfg->files.data[i]); + errc = PROGRAM_EGENERAL; + goto errcleanup; + } + + proglog("p %s", cfg->files.data[i]); + errc = nitroarc_ppack(&packer, data, (uint32_t)size, cfg->files.data[i]); + if (errc) goto errlib; + + free(data); + data = NULL; + }; + + errc = nitroarc_pseal(&packer, (void **)&data, &usize); + if (errc) goto errlib; + + *out_data = data; + *out_size = usize; + return PROGRAM_ENONE; + +errlib: + progerr("%s", nitroarc_errs(errc)); + goto errcleanup; + +errcleanup: + free(data); + free(packer.fimg_data); + free(packer.f_records); + return errc; +} + +static char* strrstem(const void *_s, int c) { + assert(_s); + + const unsigned char *s = _s; + const unsigned char *p = NULL; + + while (*s) { + if (*s == c) p = s; + s++; + } + + if (p == NULL) p = s; + + return (char *)p; +} + +static inline bool is_wordchar(int c) { + return (c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') + || c == '_'; +} + +static char* guardify(const char *name, size_t size) { + assert(name); + + char *guard = malloc(size + 1); + if (guard != NULL) { + for (size_t i = 0; i < size; i++) { + guard[i] = is_wordchar(name[i]) ? name[i] : '_'; + } + + guard[size] = 0; + } + + return guard; +} + +static int write_index(const char *fname, bool index, const strvec_t *files) { + assert(fname); + assert(files); + assert(files->data); + + if (!index) return PROGRAM_ENONE; + + char *guard = NULL; + FILE *fnaix = NULL; + char *pdot = strrstem(fname, '.'); + size_t size = pdot - fname; + char *name = malloc(size + 6); + if (name == NULL) goto erralloc; + + memcpy(name, fname, size); + memcpy(name + size, ".naix", 6); + guard = guardify(name, size + 5); + if (guard == NULL) goto erralloc; + + int errc = open_file(name, "wb", &fnaix); + if (errc) goto cleanup; + + fprintf(fnaix, "/*\n"); + fprintf(fnaix, " * This file was generated by nitroarc for '%s'\n", fname); + fprintf(fnaix, " * DO NOT MODIFY IT; MANUAL EDITS WILL BE LOST\n"); + fprintf(fnaix, " */\n"); + fprintf(fnaix, "\n"); + fprintf(fnaix, "#ifndef %s\n", guard); + fprintf(fnaix, "#define %s\n", guard); + fprintf(fnaix, "\n"); + + for (size_t i = 0; i < files->size; i++) { + char *defn = guardify(files->data[i], strlen(files->data[i])); + if (defn == NULL) { free(defn); goto erralloc; } + + fprintf(fnaix, "#define %s %zu\n", defn, i); + free(defn); + } + + fprintf(fnaix, "\n"); + fprintf(fnaix, "#define %.*s_COUNT %zu\n", (int)strlen(guard) - 5, guard, files->size); + + fprintf(fnaix, "\n"); + fprintf(fnaix, "#endif /* %s */\n", guard); + errc = PROGRAM_ENONE; + goto cleanup; + +erralloc: + progerr("alloc failure writing index file: %s", strerror(errno)); + errc = PROGRAM_EALLOC; + +cleanup: + free(name); + free(guard); + return errc; +} + +static bool strvec_has(const strvec_t *vec, char *s) { + for (size_t i = 0; i < vec->size; i++) { + if (strcmp(vec->data[i], s) == 0) return true; + } + + return false; +} + +static int strvec_grow(strvec_t *vec) { + if (vec->size + 1 >= vec->cap) { + size_t cap = vec->cap * 2; + char **tmp = realloc(vec->data, cap * sizeof(char*)); + if (tmp == NULL) return -1; + + vec->data = tmp; + vec->cap = cap; + } + + return 0; +} + +static int strvec_push(strvec_t *vec, char *s) { + if (strvec_grow(vec)) return -1; + + vec->data[vec->size] = s; + vec->size++; + return 0; +} + +static int lexicsort(const void *_lhs, const void *_rhs) { + char *const *lhs = _lhs; + char *const *rhs = _rhs; + + return strcmp(*lhs, *rhs); +} diff --git a/tools/nitroarc/src/opmode_extract.c b/tools/nitroarc/src/opmode_extract.c new file mode 100644 index 0000000000..4109f7397e --- /dev/null +++ b/tools/nitroarc/src/opmode_extract.c @@ -0,0 +1,137 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nitroarc.h" +#include "common.h" +#include "extensions.h" + +static int deduce_outdir(const options_t *opts, char **out_dirname); +static int extract_members(const nitroarc_t *narc, const char *outdir); + +extern int tool_extract(const options_t *opts) { + if (opts->file == NULL) { + progerr(PROGRAM_NOFILE); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + nitroarc_t narc = { 0 }; + char *outdir = NULL; + char *data = NULL; + size_t size = 0; + + int errc = load_file(opts->file, &data, &size) + || read_archive(data, size, &narc) + || deduce_outdir(opts, &outdir) + || set_workdir(outdir) + || extract_members(&narc, outdir) + || EXIT_SUCCESS; + + free(data); + free(outdir); + return errc; +} + +static int deduce_outdir(const options_t *opts, char **out_dirname) { + size_t size = 0; + char *name = NULL; + + if (opts->argc > 0) { + size = strlen(opts->argv[0]); + name = malloc(size + 1); + if (name == NULL) { + progerr( + "alloc failure setting up output directory '%s' for '%s': %s", + opts->argv[0], + opts->file, + strerror(errno) + ); + return PROGRAM_EALLOC; + } + + memcpy(name, opts->argv[0], size); + name[size] = 0; + } else { + size = strlen(opts->file); + name = malloc(size + 3); // append '.d' + if (name == NULL) { + progerr( + "alloc failure setting up output directory for '%s': %s", + opts->file, + strerror(errno) + ); + return PROGRAM_EALLOC; + } + + memcpy(name, opts->file, size); + name[size + 0] = '.'; + name[size + 1] = 'd'; + name[size + 2] = 0; + } + + *out_dirname = name; + return PROGRAM_ENONE; +} + +static int extract_members(const nitroarc_t *narc, const char *outdir) { + const bool named = narc->ndirs > 1; + char mname[4096] = { 0 }; + char *fname; + char *data; + uint32_t size; + + for (uint16_t i = 0; i < narc->nfiles; i++) { + int errc = nitroarc_geti(narc, i, (void **)&data, &size); + if (errc) { + progerr("error accessing member %u: %s", i, nitroarc_errs(errc)); + return PROGRAM_ELIBERROR; + } + + if (named) { + nitroarc_nameof(narc, i, mname, sizeof(mname)); + fname = &mname[1]; // Skip the leading `/` + + char *p = strchr(fname, '/'); + while (p != NULL) { + *p = 0; + if ((errc = ensure_mkdir(fname))) return errc; + *p = '/'; + p = strchr(p + 1, '/'); + } + } + else { + snprintf(mname, sizeof(mname), "%05u.%s", i, guess_extension(data)->ext); + fname = mname; + } + + proglog("x %s/%s", outdir, fname); + errc = write_file(fname, data, size); + if (errc) return errc; + } + + return PROGRAM_ENONE; +} diff --git a/tools/nitroarc/src/opmode_list.c b/tools/nitroarc/src/opmode_list.c new file mode 100644 index 0000000000..6db961e58e --- /dev/null +++ b/tools/nitroarc/src/opmode_list.c @@ -0,0 +1,201 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "nitroarc.h" +#include "common.h" +#include "extensions.h" + +static int print_members(nitroarc_t *narc, const char *format, bool header); + +extern int tool_list(const options_t *opts) { + if (opts->file == NULL) { + progerr(PROGRAM_NOFILE); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + nitroarc_t narc = { 0 }; + char *data = NULL; + size_t size = 0; + + int errc = load_file(opts->file, &data, &size) + || read_archive(data, size, &narc) + || print_members(&narc, opts->format, !opts->no_header) + || EXIT_SUCCESS; + + free(data); + return errc; +} + +static int print_members_markdown(nitroarc_t *narc, bool header, bool named); +static int print_members_csv(nitroarc_t *narc, bool header, bool named); + +typedef struct fmtfunc fmtfunc_t; +struct fmtfunc { + const char *id; + int (*func)(nitroarc_t *narc, bool header, bool named); +}; + +static const fmtfunc_t handlers[] = { + { "markdown", print_members_markdown }, + { "csv", print_members_csv }, + { 0 }, +}; + +static int print_members(nitroarc_t *narc, const char *format, bool header) { + bool named = narc->ndirs > 1; + if (format == NULL) return print_members_markdown(narc, header, named); + + const fmtfunc_t *candidate = &handlers[0]; + while (candidate->func != NULL) { + if (strcmp(format, candidate->id) == 0) break; + candidate++; + } + + if (candidate->func == NULL) { + progerr("unrecognized format '%s'", format); + return PROGRAM_EGENERAL; + } + + return candidate->func(narc, header, named); +} + +static inline ptrdiff_t ptrdiff(const void *_l, const void *_r) { + const unsigned char *l = _l; + const unsigned char *r = _r; + + return l - r; +} + +#define HEADER_MARKDOWN_1 "| Image Offset (rel) | Image Offset (abs) | Image Size (bytes) |\n" +#define HEADER_MARKDOWN_2 "| -----------------: | -----------------: | -----------------: |" +#define HEADER_MARKDOWN_INDEX "| Index | File Type " HEADER_MARKDOWN_1 \ + "| :---- | --------- " HEADER_MARKDOWN_2 + +#define HEADER_MARKDOWN_NAME " | Path " HEADER_MARKDOWN_1 \ + " | :--- " HEADER_MARKDOWN_2 + +#define printf_members(narc, format, ...) \ + do { \ + for (uint16_t i = 0; i < narc->nfiles && i < 0xF000; i++) { \ + int errc = nitroarc_geti(narc, i, (void **)&mdata, &msize); \ + if (errc) { \ + progerr("%s", nitroarc_errs(errc)); \ + return PROGRAM_ELIBERROR; \ + } \ + \ + nitroarc_nameof(narc, i, mname, sizeof(mname)); \ + printf(format, __VA_ARGS__); \ + } \ + } while (0) + +static int print_members_markdown(nitroarc_t *narc, bool header, bool named) { + const void *mdata = NULL; + uint32_t msize = 0; + char mname[4096] = { 0 }; + size_t max_namelen = 0; + + if (named) { + for (uint16_t i = 0; i < narc->nfiles && i < 0xF000; i++) { + int errc = nitroarc_nameof(narc, i, mname, sizeof(mname)); + if (errc) { + progerr("%s", nitroarc_errs(errc)); + return PROGRAM_ELIBERROR; + } + + size_t namelen = strlen(mname); + max_namelen = max_namelen < namelen ? namelen : max_namelen; + } + + if (header) { + printf("| %-*s %s", (int)max_namelen, "Path", HEADER_MARKDOWN_1); + printf("| :"); + for (size_t i = 0; i < max_namelen - 1; i++) putc('-', stdout); + printf(" %s\n", HEADER_MARKDOWN_2); + } + + printf_members( + narc, + "| %-*s | 0x%08X | 0x%08X | %10u |\n", + (int)max_namelen, + mname, + (uint32_t)ptrdiff(mdata, narc->fimg.data), + (uint32_t)ptrdiff(mdata, narc->head), + msize + ); + + return NITROARC_ESUCCESS; + } + + if (header) puts(HEADER_MARKDOWN_INDEX); + printf_members( + narc, + "| %5d | %-9s | 0x%08X | 0x%08X | %10u |\n", + i, + guess_extension(mdata)->ext, + (uint32_t)ptrdiff(mdata, narc->fimg.data), + (uint32_t)ptrdiff(mdata, narc->head), + msize + ); + + return NITROARC_ESUCCESS; +} + +#define HEADER_CSV "Image Offset (rel),Image Offset (abs),Image Size (bytes)" +#define HEADER_CSV_INDEX "Index,File Type" HEADER_CSV +#define HEADER_CSV_NAME "Name," HEADER_CSV + +static int print_members_csv(nitroarc_t *narc, bool header, bool named) { + char mname[4096] = { 0 }; + const void *mdata = NULL; + uint32_t msize = 0; + + if (named) { + if (header) puts(HEADER_CSV_NAME); + printf_members( + narc, + "%s,0x%08X,0x%08X,%u\n", + mname, + (uint32_t)ptrdiff(mdata, narc->fimg.data), + (uint32_t)ptrdiff(mdata, narc->head), + msize + ); + + return NITROARC_ESUCCESS; + } + + if (header) puts(HEADER_CSV_INDEX); + printf_members( + narc, + "%d,%s,0x%08X,0x%08X,%u\n", + i, + guess_extension(mdata)->ext, + (uint32_t)ptrdiff(mdata, narc->fimg.data), + (uint32_t)ptrdiff(mdata, narc->head), + msize + ); + + return NITROARC_ESUCCESS; +} diff --git a/tools/nitroarc/src/opmode_metadata.c b/tools/nitroarc/src/opmode_metadata.c new file mode 100644 index 0000000000..7e5d983407 --- /dev/null +++ b/tools/nitroarc/src/opmode_metadata.c @@ -0,0 +1,117 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include "nitroarc.h" +#include "common.h" + +static int print_metadata(const nitroarc_t *narc, const options_t *opts); + +extern int tool_metadata(const options_t *opts) { + if (opts->file == NULL) { + progerr(PROGRAM_NOFILE); + progerr(PROGRAM_HELP, opts->name); + return EXIT_FAILURE; + } + + nitroarc_t narc = { 0 }; + char *data = NULL; + size_t size = 0; + + int errc = load_file(opts->file, &data, &size) + || read_archive(data, size, &narc) + || print_metadata(&narc, opts) + || EXIT_SUCCESS; + + free(data); + return errc; +} + +static int print_metadata_markdown(const nitroarc_t *narc, bool header); +static int print_metadata_csv(const nitroarc_t *narc, bool header); + +typedef struct fmtfunc fmtfunc_t; +struct fmtfunc { + const char *id; + int (*func)(const nitroarc_t *narc, bool header); +}; + +static const fmtfunc_t handlers[] = { + { "markdown", print_metadata_markdown }, + { "csv", print_metadata_csv }, + { 0 }, +}; + +static int print_metadata(const nitroarc_t *narc, const options_t *opts) { + bool header = !opts->no_header; + if (opts->format == NULL) return print_metadata_markdown(narc, header); + + const fmtfunc_t *candidate = &handlers[0]; + while (candidate->func != NULL) { + if (strcmp(opts->format, candidate->id) == 0) break; + candidate++; + } + + if (candidate->func == NULL) { + progerr("unrecognized format '%s'", opts->format); + return PROGRAM_EGENERAL; + } + + return candidate->func(narc, header); +} + +#define putf printf // Only for nice alignment below + +#define HEADER_MARKDOWN "| Section | Size (bytes) | Header Offset (abs) | Data Offset (abs) | Entry Count |\n" \ + "| :------ | -----------: | ------------------: | ----------------: | ----------: |" +#define ROW_MARKDOWN "| %s | %10u | 0x%08X | 0x%08X | %5u |\n" + +static int print_metadata_markdown(const nitroarc_t *narc, bool header) { + const nitroarc_fatb_t *fatb = &narc->fatb; + const nitroarc_fntb_t *fntb = &narc->fntb; + const nitroarc_fimg_t *fimg = &narc->fimg; + + if (header) puts(HEADER_MARKDOWN); + putf(ROW_MARKDOWN, "NARC", narc->size, 0, fatb->ofs_head, 3); + putf(ROW_MARKDOWN, "FATB", fatb->size, fatb->ofs_head, fatb->ofs_data, narc->nfiles); + putf(ROW_MARKDOWN, "FNTB", fntb->size, fntb->ofs_head, fntb->ofs_data, narc->ndirs); + putf(ROW_MARKDOWN, "FIMG", fimg->size, fimg->ofs_head, fimg->ofs_data, narc->nfiles); + + return PROGRAM_ENONE; +} + +#define HEADER_CSV "Section,Size (bytes),Header Offset (abs),Data Offset (abs),Entry Count" +#define ROW_CSV "%s,%u,0x%08X,0x%08X,%u\n" + +static int print_metadata_csv(const nitroarc_t *narc, bool header) { + const nitroarc_fatb_t *fatb = &narc->fatb; + const nitroarc_fntb_t *fntb = &narc->fntb; + const nitroarc_fimg_t *fimg = &narc->fimg; + + if (header) puts(HEADER_CSV); + putf(ROW_CSV, "NARC", narc->size, 0, fatb->ofs_head, 3); + putf(ROW_CSV, "FATB", fatb->size, fatb->ofs_head, fatb->ofs_data, narc->nfiles); + putf(ROW_CSV, "FNTB", fntb->size, fntb->ofs_head, fntb->ofs_data, narc->ndirs); + putf(ROW_CSV, "FIMG", fimg->size, fimg->ofs_head, fimg->ofs_data, narc->nfiles); + + return PROGRAM_ENONE; +} diff --git a/tools/nitroarc/src/optparse.c b/tools/nitroarc/src/optparse.c new file mode 100644 index 0000000000..487c206567 --- /dev/null +++ b/tools/nitroarc/src/optparse.c @@ -0,0 +1,126 @@ +#include "optparse.h" + +#include +#include +#include + +#define errorf(fmt, ...) \ + snprintf( \ + parser->errmsg, \ + OPT_ERRMSG_MAX, \ + fmt, \ + __VA_ARGS__ \ + ) + +#define ERR_MISSING_ARG "missing argument for option" +#define ERR_UNKNOWN_OPT "unrecognized option" +#define ERR_UNEXPECTED_ARG "unexpected argument '%s' for option" +#define ERR_MISSING_ARG_SHORT ERR_MISSING_ARG " -%c" +#define ERR_UNKNOWN_OPT_SHORT ERR_UNKNOWN_OPT " -%c" +#define ERR_MISSING_ARG_LONG ERR_MISSING_ARG " --%s" +#define ERR_UNKNOWN_OPT_LONG ERR_UNKNOWN_OPT " --%s" +#define ERR_UNEXPECTED_ARG_LONG ERR_UNEXPECTED_ARG " --%s" + +static bool matchopt_short( + const char *option, + int shortind, + const option_cfg_t *config +) { + char c = option[shortind]; + return c != 0 && (c == config->shortopt || c == config->shortalias); +} + +static int parseopt_short(optparser_t *parser, const char *option) { + for (int i = 0; parser->options[i].longopt; i++) { + const option_cfg_t *candidate = &parser->options[i]; + if (!matchopt_short(option, parser->shortind, candidate)) continue; + + if (candidate->hasarg) { + if (option[parser->shortind + 1] != '\0') { + parser->optarg = (void *)&option[parser->shortind + 1]; + parser->shortind = 1; // reset for next short-option chain + parser->optind++; // prepare for the next option + return i; + } + + if (parser->argv[parser->optind + 1] == NULL) { + errorf(ERR_MISSING_ARG_SHORT, option[parser->shortind]); + return i; + } + + parser->optarg = parser->argv[parser->optind + 1]; + parser->shortind = 1; // reset for next short-option chain + parser->optind += 2; // prepare for the next option + return i; + } + + parser->shortind++; + return i; + } + + errorf(ERR_UNKNOWN_OPT_SHORT, option[parser->shortind]); + return OPT_ERROR; +} + +static bool matchopt_long(const char *option, const option_cfg_t *config) { + return strcmp(option, config->longopt) == 0 + || (config->longalias && strcmp(option, config->longalias) == 0); +} + +static int parseopt_long(optparser_t *parser, const char *option) { + option += 2; // skip the leading '--' + + char *poseq = strchr(option, '='); + if (poseq) *poseq = '\0'; + + for (int i = 0; parser->options[i].longopt; i++) { + const option_cfg_t *candidate = &parser->options[i]; + if (!matchopt_long(option, candidate)) continue; + + if (!candidate->hasarg) { // simple flag, no argument + if (poseq) { + errorf(ERR_UNEXPECTED_ARG_LONG, &poseq[1], option); + return i; + } + + parser->optind++; + return i; + } + + if (poseq == NULL) { + if (parser->argv[parser->optind + 1] == NULL) { + errorf(ERR_MISSING_ARG_LONG, option); + return i; + } + + parser->optarg = parser->argv[parser->optind + 1]; + parser->optind += 2; // prepare for the next option + return i; + } + + if (poseq[1] == '\0') { + errorf(ERR_MISSING_ARG_LONG, option); + return i; + } + + parser->optarg = poseq + 1; + parser->optind++; // prepare for the next option + return i; + } + + errorf(ERR_UNKNOWN_OPT_LONG, option); + return OPT_ERROR; +} + +int parseopt(optparser_t *parser) { + char *option = parser->argv[parser->optind]; + if (option == NULL) return OPT_DONE; // no more options + if (option[0] != '-') return OPT_DONE; // no more options + if (option[1] == '\0') return OPT_DONE; // literal '-' is an argument + if (option[1] != '-') return parseopt_short(parser, option); + if (option[2] != '\0') return parseopt_long(parser, option); + + // option is '--'; no more options + parser->optind++; + return OPT_DONE; +} diff --git a/tools/nitroarc/src/optparse.h b/tools/nitroarc/src/optparse.h new file mode 100644 index 0000000000..9190061dc9 --- /dev/null +++ b/tools/nitroarc/src/optparse.h @@ -0,0 +1,51 @@ +/* + * nitroarc - an archiving utility for Nintendo's Nitro Archive format + * Copyright (C) 2026 Rachel + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef TOOL_OPTION_H +#define TOOL_OPTION_H + +#include + +#define OPT_DONE -2 +#define OPT_ERROR -1 + +#define OPT_ERRMSG_MAX 96 + +typedef struct option_cfg option_cfg_t; +struct option_cfg { + const char *longopt; + const char *longalias; + char shortopt; + char shortalias; + bool hasarg; +}; + +typedef struct optparser optparser_t; +struct optparser { + char **argv; + int optind; + int shortind; + char *optarg; + char errmsg[OPT_ERRMSG_MAX]; + + const option_cfg_t *options; +}; + +int parseopt(optparser_t *parser); + +#endif // TOOL_OPTION_H diff --git a/tools/scripts/make_pl_growtbl.py b/tools/scripts/make_pl_growtbl.py index a68dfa2168..55479d7be8 100755 --- a/tools/scripts/make_pl_growtbl.py +++ b/tools/scripts/make_pl_growtbl.py @@ -48,4 +48,9 @@ with open(args.table) as data_file: target_file.write(out) count += 1 -subprocess.run([args.narc, 'create', '--output', output_dir / 'pl_growtbl.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', output_dir / 'pl_growtbl.narc', + private_dir +]) diff --git a/tools/scripts/make_pl_otherpoke.py b/tools/scripts/make_pl_otherpoke.py index f3654ddea0..6d12d210da 100755 --- a/tools/scripts/make_pl_otherpoke.py +++ b/tools/scripts/make_pl_otherpoke.py @@ -107,4 +107,10 @@ subprocess.run([ '-comp', '10' ]) -subprocess.run([args.narc, 'create', '--naix', '--output', output_dir / 'pl_otherpoke.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--index', + '--file', output_dir / 'pl_otherpoke.narc', + private_dir +]) diff --git a/tools/scripts/make_pl_poke_icon.py b/tools/scripts/make_pl_poke_icon.py index 42c6c1f8a5..073b4dea4b 100755 --- a/tools/scripts/make_pl_poke_icon.py +++ b/tools/scripts/make_pl_poke_icon.py @@ -70,9 +70,10 @@ for i, input_fname in enumerate(args.icon_files): ]) subprocess.run([ - args.narc, "create", - "--naix", - "--order", args.order_file, - "--output", output_dir / "pl_poke_icon.narc", + args.narc, + "--create", + "--index", + "--files-from", args.order_file, + "--file", output_dir / "pl_poke_icon.narc", bin_dest_dir, ]) diff --git a/tools/scripts/make_pl_pokegra.py b/tools/scripts/make_pl_pokegra.py index 9c989cc3f1..a55e24501c 100755 --- a/tools/scripts/make_pl_pokegra.py +++ b/tools/scripts/make_pl_pokegra.py @@ -84,4 +84,9 @@ for i, subdir in enumerate(SPECIES_DIRS): '-comp', '10' ]) -subprocess.run([args.narc, 'create', '--output', output_dir / 'pl_pokegra.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', output_dir / 'pl_pokegra.narc', + private_dir +]) diff --git a/tools/scripts/make_pl_pokezukan.py b/tools/scripts/make_pl_pokezukan.py index db536a3d85..14f025bf89 100755 --- a/tools/scripts/make_pl_pokezukan.py +++ b/tools/scripts/make_pl_pokezukan.py @@ -68,4 +68,9 @@ with open(target_fname, 'wb+') as target_file: pl_pokezukan[i*2 + 1] = (pokedex[i] >> 8) & 0xff target_file.write(bytes(pl_pokezukan)) -subprocess.run([args.narc, 'create', '--output', output_dir / 'pl_pokezukan.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', output_dir / 'pl_pokezukan.narc', + private_dir +]) diff --git a/tools/scripts/make_pokedex_data.py b/tools/scripts/make_pokedex_data.py index 2928644bcd..81326ec29b 100755 --- a/tools/scripts/make_pokedex_data.py +++ b/tools/scripts/make_pokedex_data.py @@ -186,4 +186,9 @@ for i in range(NUM_FILES): with open(target_fname, 'wb+') as target_file: target_file.write(binData[i]) -subprocess.run([args.narc, 'create', '--output', str(output_dir / output_name) + '.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', f'{output_dir / output_name}.narc', + private_dir +]) diff --git a/tools/scripts/make_pokedex_enc_platinum.py b/tools/scripts/make_pokedex_enc_platinum.py index 39eab666e5..4f4cfb74bc 100755 --- a/tools/scripts/make_pokedex_enc_platinum.py +++ b/tools/scripts/make_pokedex_enc_platinum.py @@ -18,7 +18,7 @@ argparser = argparse.ArgumentParser( ) argparser.add_argument('-n', '--narc', required=True, - help='Path to narc executable') + help='Path to narc compiler tool') argparser.add_argument('-s', '--source-dir', required=True, help='Path to the source directory (res/field/encounters)') @@ -459,4 +459,9 @@ for species in range(NUM_POKEMON): with open(target_fname, 'wb+') as target_file: target_file.write(bin_data) -subprocess.run([args.narc, 'create', '--output', str(output_dir / output_name) + '.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', f'{output_dir / output_name}.narc', + private_dir, +]) diff --git a/tools/scripts/make_shinzukan.py b/tools/scripts/make_shinzukan.py index 752bf7dee8..12aa9e84e1 100755 --- a/tools/scripts/make_shinzukan.py +++ b/tools/scripts/make_shinzukan.py @@ -67,7 +67,12 @@ with open(target_fname, 'wb+') as target_file: shinzukan[i*2 + 1] = (pokedex[i] >> 8) & 0xff target_file.write(bytes(shinzukan)) -subprocess.run([args.narc, 'create', '--output', output_dir / 'shinzukan.narc', private_dir]) +subprocess.run([ + args.narc, + '--create', + '--file', output_dir / 'shinzukan.narc', + private_dir +]) # generate header for dex size constants NUM_NATIONAL = len(Species)