├── tests ├── include │ ├── dummy.asm │ ├── deep │ │ ├── deeper │ │ │ ├── deepest │ │ │ │ └── data.bin │ │ │ └── data.asm │ │ └── data.asm │ ├── incsrcxkas-2.asm │ ├── loop1.asm │ ├── loop2.asm │ └── data.asm ├── misc.asm ├── badsublabel.asm ├── stdinclude │ └── std │ │ └── test.asm ├── commabrokenquotes.asm ├── data │ ├── filename with spaces.bin │ ├── pushtable1.asm │ ├── pushtable2.asm │ ├── table.asm │ └── 64kb.bin ├── setlabel.asm ├── assert-pass.asm ├── badrep.asm ├── includeonce │ ├── path1 │ │ ├── path2 │ │ │ └── test.asm │ │ └── test.asm │ ├── path2 │ │ └── test.asm │ ├── path3 │ │ └── test.asm │ └── test.asm ├── incsrcloop.asm ├── define-quotes.asm ├── emptysublabel.asm ├── include-dir.asm ├── readoob.asm ├── builtindefinesfail.asm ├── labela.asm ├── pseudo-opcodes.asm ├── trailingcomma.asm ├── functest3.asm ├── half_bank_check.asm ├── assert-fail.asm ├── dd.asm ├── incbin_error.asm ├── divbyforwardtable.asm ├── global_label_error_sublabel.asm ├── warnings-2.asm ├── sa1freespace.asm ├── warnings-3.asm ├── global_label_error_duplicate.asm ├── incsrcxkas-1.asm ├── includeonce.asm ├── db-spc.asm ├── global_label_error_macrolabel.asm ├── warn-immediate.asm ├── freespaceshrink.asm ├── spc-inline.asm ├── warnings-1.asm ├── incbin.asm ├── warnings-4.asm ├── includehierarchy.asm ├── autoclean.asm ├── realbase.asm ├── 32bitvalues.asm ├── freespacealign.asm ├── mappers.asm ├── bank_shorthand.asm ├── functest2.asm ├── 0x.asm ├── archswitch.asm ├── functest1.asm ├── fill.asm ├── datasize.asm ├── optimization-warn.asm ├── sfxfreespace.asm ├── prot.asm ├── read.asm ├── spcblock.asm ├── spcsynonyms.asm ├── protonbankstart.asm ├── datasize_freespace.asm ├── nestedpushpcfreespace.asm ├── nesteddefines.asm ├── builtindefinespass.asm ├── pushpullns.asm ├── fastrom.asm ├── bigincbin.asm ├── macronoarg.asm ├── multiprot.asm ├── autoclean_2freecode_to_1freecode.asm ├── autoclean_twice.asm ├── xkasemu.asm ├── sa1bankswitch.asm ├── tablefiles.asm ├── forloop.asm ├── labels_static_fail.asm ├── global_label_success.asm ├── variadic_syntax.asm ├── sa1altmapper.asm ├── macrolabels.asm ├── namespaces.asm ├── escaping.asm ├── variadic_errors.asm ├── advanced-prints.asm ├── v160features.asm ├── labels_static_pass.asm ├── std.asm ├── structs.asm ├── elseif.asm ├── bankcross.asm ├── v150features.asm ├── optimizer.asm ├── 120freespaces.asm ├── arch-65816.asm ├── opcodesize.asm └── v140features.asm ├── dummy_rom.sfc ├── src ├── asar │ ├── res │ │ └── windows │ │ │ ├── asar.ico │ │ │ ├── asar_lib.rc │ │ │ └── asar.rc │ ├── crc32.h │ ├── interface-shared.h │ ├── lib │ │ ├── libasar.pc.in │ │ └── JoinPaths.cmake │ ├── arch-shared.h │ ├── platform │ │ ├── file-helpers.h │ │ ├── generic │ │ │ └── file-helpers-generic.cpp │ │ ├── linux │ │ │ └── file-helpers-linux.cpp │ │ ├── windows │ │ │ └── file-helpers-win32.cpp │ │ └── file-helpers.cpp │ ├── asar_math.h │ ├── libcon.h │ ├── macro.h │ ├── std-includes.h │ ├── libmisc.h │ ├── dll_helper.h │ ├── addr2line.h │ ├── virtualfile.h │ ├── addr2line.cpp │ ├── warnings.h │ ├── assembleblock.h │ ├── asar.h │ ├── autoarray.h │ ├── libcon.cpp │ ├── libsmw.h │ ├── crc32.cpp │ └── virtualfile.cpp ├── CMakeLists.txt ├── generate_manual_tables.py ├── asar-tests │ └── CMakeLists.txt └── asar-dll-bindings │ └── c │ ├── asardll.c │ └── asar.h ├── docs ├── shared │ ├── highlight_js │ │ └── README.txt │ ├── common.js │ └── highlight_js_asar │ │ ├── styles │ │ └── default.css │ │ └── highlight_js_asar.js ├── index.html └── manual │ └── warnings-list.html ├── cmake ├── mingw-x64.cmake ├── mingw-x86.cmake └── _mingw-common.cmake ├── run_tests.sh ├── run_tests.bat ├── dummy_rom.asm ├── license-wtfpl.txt ├── .gitignore ├── .github └── workflows │ ├── docs-deploy.yml │ └── cmake.yml ├── generate_release_zip.py ├── README.txt ├── LICENSE ├── ext ├── sublime-text │ └── 65c816.sublime-syntax └── notepad-plus-plus │ └── syntax-highlighting.xml └── README.md /tests/include/dummy.asm: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/misc.asm: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/include/deep/deeper/deepest/data.bin: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /tests/include/incsrcxkas-2.asm: -------------------------------------------------------------------------------- 1 | 2 | ;@xkas -------------------------------------------------------------------------------- /tests/badsublabel.asm: -------------------------------------------------------------------------------- 1 | ;`errEunknown_command 2 | . -------------------------------------------------------------------------------- /tests/include/loop1.asm: -------------------------------------------------------------------------------- 1 | incsrc "loop2.asm" 2 | -------------------------------------------------------------------------------- /tests/include/loop2.asm: -------------------------------------------------------------------------------- 1 | incsrc "loop1.asm" 2 | -------------------------------------------------------------------------------- /tests/stdinclude/std/test.asm: -------------------------------------------------------------------------------- 1 | !stdincluded ?= 1 2 | -------------------------------------------------------------------------------- /tests/commabrokenquotes.asm: -------------------------------------------------------------------------------- 1 | ;`errEmismatched_quotes 2 | ," -------------------------------------------------------------------------------- /tests/data/filename with spaces.bin: -------------------------------------------------------------------------------- 1 |  2 |  -------------------------------------------------------------------------------- /tests/setlabel.asm: -------------------------------------------------------------------------------- 1 | ;`04 2 | a = 4 3 | org $008000 4 | db a -------------------------------------------------------------------------------- /tests/assert-pass.asm: -------------------------------------------------------------------------------- 1 | assert 1 2 | org $8000 3 | assert pc() < $8001 4 | -------------------------------------------------------------------------------- /tests/badrep.asm: -------------------------------------------------------------------------------- 1 | ;`errEinvalid_number 2 | org $008000 3 | rep #$0020 : nop -------------------------------------------------------------------------------- /tests/includeonce/path1/path2/test.asm: -------------------------------------------------------------------------------- 1 | includeonce 2 | 3 | db $04 4 | -------------------------------------------------------------------------------- /dummy_rom.sfc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPGHacker/asar/HEAD/dummy_rom.sfc -------------------------------------------------------------------------------- /tests/data/pushtable1.asm: -------------------------------------------------------------------------------- 1 | 'A' = $00 2 | 'B' = $01 3 | 'C' = $02 4 | 'D' = $03 -------------------------------------------------------------------------------- /tests/data/pushtable2.asm: -------------------------------------------------------------------------------- 1 | 'A' = $04 2 | 'B' = $05 3 | 'C' = $06 4 | 'D' = $07 -------------------------------------------------------------------------------- /tests/include/data.asm: -------------------------------------------------------------------------------- 1 | 2 | db $02 3 | incsrc "deep/data.asm" 4 | db $08 5 | -------------------------------------------------------------------------------- /tests/incsrcloop.asm: -------------------------------------------------------------------------------- 1 | ;`errErecursion_limit 2 | incsrc "include/loop1.asm" 3 | -------------------------------------------------------------------------------- /tests/data/table.asm: -------------------------------------------------------------------------------- 1 | 'A' = $12345678 2 | 'B' = $123456 3 | 'C' = $1234 4 | 'D' = $12 -------------------------------------------------------------------------------- /tests/define-quotes.asm: -------------------------------------------------------------------------------- 1 | ;`errEmismatched_quotes 2 | !w = "a""b" 3 | print "!w" 4 | -------------------------------------------------------------------------------- /tests/include/deep/data.asm: -------------------------------------------------------------------------------- 1 | 2 | db $03 3 | incsrc "deeper/data.asm" 4 | db $07 5 | -------------------------------------------------------------------------------- /tests/data/64kb.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPGHacker/asar/HEAD/tests/data/64kb.bin -------------------------------------------------------------------------------- /tests/emptysublabel.asm: -------------------------------------------------------------------------------- 1 | ;`errEunknown_command 2 | 3 | org $008000 4 | 5 | asdf: 6 | . -------------------------------------------------------------------------------- /tests/include-dir.asm: -------------------------------------------------------------------------------- 1 | ;`errEfailed_to_open_not_regular_file 2 | incbin "include" 3 | -------------------------------------------------------------------------------- /tests/readoob.asm: -------------------------------------------------------------------------------- 1 | ;`errEsnes_address_out_of_bounds 2 | 3 | org 32768 4 | db read1(32768) -------------------------------------------------------------------------------- /tests/builtindefinesfail.asm: -------------------------------------------------------------------------------- 1 | ;`errEoverriding_builtin_define 2 | !assembler = "not_asar" 3 | -------------------------------------------------------------------------------- /tests/includeonce/path2/test.asm: -------------------------------------------------------------------------------- 1 | includeonce 2 | 3 | db $05 4 | incsrc "../path1/test.asm" 5 | -------------------------------------------------------------------------------- /tests/labela.asm: -------------------------------------------------------------------------------- 1 | ;`F0 FE 2 | ;`warnWfeature_deprecated 3 | 4 | org 32768 5 | a: 6 | BEQ a 7 | -------------------------------------------------------------------------------- /src/asar/res/windows/asar.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RPGHacker/asar/HEAD/src/asar/res/windows/asar.ico -------------------------------------------------------------------------------- /tests/pseudo-opcodes.asm: -------------------------------------------------------------------------------- 1 | ;`C8 0A 0A 4A 4A 4A 2 | 3 | org $008000 4 | inx #0 5 | iny #1 6 | asl #2 7 | lsr #3 8 | -------------------------------------------------------------------------------- /tests/trailingcomma.asm: -------------------------------------------------------------------------------- 1 | ;`FF FF FF FF FF FF FF 2 | org $8000 3 | db $FF,$FF,$FF, 4 | $FF,$FF, 5 | $FF, 6 | $FF -------------------------------------------------------------------------------- /tests/functest3.asm: -------------------------------------------------------------------------------- 1 | ;`03 2 | 3 | function test(abc,ab) = abc+ab 4 | 5 | org $8000 6 | 7 | main: 8 | db test(1,2) 9 | -------------------------------------------------------------------------------- /tests/half_bank_check.asm: -------------------------------------------------------------------------------- 1 | ;`errEbank_border_crossed 2 | hirom 3 | check bankcross half 4 | org $C07FFF 5 | dw $0000 6 | -------------------------------------------------------------------------------- /tests/assert-fail.asm: -------------------------------------------------------------------------------- 1 | ;`errEassertion_failed 2 | ;`errEassertion_failed 3 | assert 0 4 | org $8002 5 | assert pc() < $8002 6 | -------------------------------------------------------------------------------- /tests/dd.asm: -------------------------------------------------------------------------------- 1 | ;`FF FF FF 7F 2 | ;`FF FF FF FF 3 | ;`00 00 00 80 4 | 5 | org $008000 6 | dd $7FFFFFFF 7 | dd $FFFFFFFF 8 | dd $80000000 -------------------------------------------------------------------------------- /tests/incbin_error.asm: -------------------------------------------------------------------------------- 1 | ;`errEmismatched_parentheses 2 | ;`warnWfeature_deprecated 3 | incbin "data/64kb.bin":(2+2)+(1+3)-($8000) 4 | -------------------------------------------------------------------------------- /tests/divbyforwardtable.asm: -------------------------------------------------------------------------------- 1 | ;`40 2 | ;`00 00 00 00 3 | ;`00 00 4 | org $008000 5 | db $80/(Label2-Label1) 6 | dd 0 7 | Label1: 8 | dw 0 9 | Label2: -------------------------------------------------------------------------------- /tests/global_label_error_sublabel.asm: -------------------------------------------------------------------------------- 1 | ;`errEinvalid_global_label 2 | lorom 3 | org $008000 4 | 5 | label: 6 | global globlabel: 7 | global .label -------------------------------------------------------------------------------- /tests/includeonce/path3/test.asm: -------------------------------------------------------------------------------- 1 | includeonce 2 | 3 | db $06 4 | incsrc "../path1/test.asm" 5 | incsrc "./../path2/../path1/../path2/test.asm" 6 | -------------------------------------------------------------------------------- /tests/warnings-2.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`errEpushwarnings_without_pullwarnings 3 | 4 | warnings push 5 | warnings disable Wmissing_org 6 | 7 | db $01 8 | -------------------------------------------------------------------------------- /tests/includeonce/test.asm: -------------------------------------------------------------------------------- 1 | includeonce 2 | 3 | db $02 4 | incsrc "path1/test.asm" 5 | incsrc "path2/../path2/test.asm" 6 | incsrc "./path3/./test.asm" -------------------------------------------------------------------------------- /tests/sa1freespace.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07FD7 0A 3 | ;`80000 53 54 41 52 03 00 FC FF 4 | ;`EA EA EA EA 5 | ;`FFFFF 00 6 | sa1rom 7 | freecode cleaned 8 | NOP #4 -------------------------------------------------------------------------------- /tests/warnings-3.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`errEpullwarnings_without_pushwarnings 3 | 4 | warnings disable Wmissing_org 5 | 6 | db $01 7 | 8 | warnings pull 9 | -------------------------------------------------------------------------------- /tests/global_label_error_duplicate.asm: -------------------------------------------------------------------------------- 1 | ;`errElabel_redefined 2 | 3 | lorom 4 | org $008000 5 | 6 | label: 7 | .sublabel 8 | global #globlabel: 9 | .sublabel -------------------------------------------------------------------------------- /tests/incsrcxkas-1.asm: -------------------------------------------------------------------------------- 1 | ;`errEcommand_in_non_root_file 2 | ;`warnWfeature_deprecated 3 | ;`warnWfeature_deprecated 4 | incsrc "include/incsrcxkas-2.asm" 5 | -------------------------------------------------------------------------------- /tests/include/deep/deeper/data.asm: -------------------------------------------------------------------------------- 1 | 2 | macro include_in_macro() 3 | db $04 4 | incbin "deepest/data.bin" 5 | db $06 6 | endmacro 7 | 8 | %include_in_macro() -------------------------------------------------------------------------------- /tests/includeonce.asm: -------------------------------------------------------------------------------- 1 | ;`01 02 03 04 05 06 07 2 | 3 | asar 1.60 4 | 5 | org $008000 6 | 7 | db $01 8 | incsrc "includeonce/test.asm" 9 | db $07 10 | -------------------------------------------------------------------------------- /tests/db-spc.asm: -------------------------------------------------------------------------------- 1 | ;`00 01 02 03 2 | warnings disable Wfeature_deprecated 3 | arch spc700-raw 4 | 5 | org $000000 6 | 7 | db $00 8 | db $01 9 | db $02, $03 10 | -------------------------------------------------------------------------------- /tests/global_label_error_macrolabel.asm: -------------------------------------------------------------------------------- 1 | ;`errEinvalid_global_label 2 | 3 | macro Test() 4 | global ?label 5 | endmacro 6 | 7 | lorom 8 | org $008000 9 | 10 | %Test() -------------------------------------------------------------------------------- /tests/warn-immediate.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`29 78 3 | ;`warnWimplicitly_sized_immediate 4 | 5 | warnings enable Wimplicitly_sized_immediate 6 | 7 | org $008000 8 | 9 | and #120 10 | -------------------------------------------------------------------------------- /tests/freespaceshrink.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07FD7 0A 3 | ;`FFFFF 00 4 | ;`80000 5 | ;`53 54 41 52 05 00 FA FF AD 0E 80 AD 0E 80 6 | 7 | freecode cleaned 8 | lda lbl 9 | lda lbl 10 | lbl: 11 | -------------------------------------------------------------------------------- /src/asar/crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic crc32 helper function 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | extern uint32_t crc32(const uint8_t *s, unsigned int len); 10 | -------------------------------------------------------------------------------- /tests/spc-inline.asm: -------------------------------------------------------------------------------- 1 | ;`03 00 00 50 2 | ;`5F 03 50 3 | ;`00 00 00 00 4 | warnings disable Wfeature_deprecated 5 | org $008000 6 | arch spc700-inline 7 | org $5000 8 | jmp lab 9 | lab: 10 | -------------------------------------------------------------------------------- /tests/warnings-1.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`01 3 | ;`warnWfeature_deprecated 4 | 5 | warnings push 6 | warnings disable Wmissing_org 7 | warnings disable W1008 8 | 9 | db $01 10 | 11 | warnings pull 12 | -------------------------------------------------------------------------------- /tests/incbin.asm: -------------------------------------------------------------------------------- 1 | ;`56 78 2 | ;`12 34 3 | ;`05 06 07 4 | org $8000 5 | incbin "data/64kb.bin":$8000..$8002 6 | incbin "data/64kb.bin":$7FFE..$8000 7 | incbin "data/filename with spaces.bin":2+2..8-1 8 | 9 | -------------------------------------------------------------------------------- /tests/warnings-4.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`01 3 | ;`warnWmissing_org 4 | 5 | warnings push 6 | 7 | warnings disable Wmissing_org 8 | warnings enable Wmissing_org 9 | 10 | db $01 11 | 12 | warnings pull 13 | -------------------------------------------------------------------------------- /tests/includehierarchy.asm: -------------------------------------------------------------------------------- 1 | ;`01 02 03 04 05 06 07 08 09 2 | ;`04 05 06 3 | 4 | asar 1.60 5 | 6 | org $008000 7 | 8 | db $01 9 | incsrc "include/data.asm" 10 | db $09 11 | 12 | %include_in_macro() 13 | -------------------------------------------------------------------------------- /docs/shared/highlight_js/README.txt: -------------------------------------------------------------------------------- 1 | Update procedure: 2 | * go to https://highlightjs.org/download 3 | * select bash, dos, plaintext, powershell, python 4 | * download 5 | * copy only the highlight.min.js file here 6 | -------------------------------------------------------------------------------- /tests/autoclean.asm: -------------------------------------------------------------------------------- 1 | ;`+ #2 2 | ;`00000 5C 08 80 90 3 | ;`07FD7 0A 4 | ;`80000 53 54 41 52 00 00 FF FF EA 5 | ;`FFFFF 00 6 | 7 | org $008000 8 | autoclean JML Mymain 9 | 10 | freecode 11 | Mymain: 12 | NOP -------------------------------------------------------------------------------- /tests/realbase.asm: -------------------------------------------------------------------------------- 1 | ;`34 12 7E 2 | ;`00 80 00 3 | ;`34 12 7E 4 | 5 | org $008000 6 | base $7E1234 7 | label: 8 | label_pc = realbase() 9 | label3 = pc() 10 | 11 | dl label 12 | dl label_pc 13 | dl label3 14 | -------------------------------------------------------------------------------- /tests/32bitvalues.asm: -------------------------------------------------------------------------------- 1 | ;`FF 2 | ;`FF FF FF FF 3 | ;`21 43 65 87 4 | ;`FF FF FF FF 5 | ;`00 00 FF 00 6 | 7 | org $8000 8 | 9 | db -1 10 | dd $FFFFFFFF 11 | dd $87654321+0 12 | dd (-2)/2 13 | dd $FF000000/256 14 | -------------------------------------------------------------------------------- /tests/includeonce/path1/test.asm: -------------------------------------------------------------------------------- 1 | includeonce 2 | 3 | db $03 4 | incsrc "path2/test.asm" 5 | incsrc "path2/test.asm" 6 | incsrc "path2/test.asm" 7 | incsrc "path2/./test.asm" 8 | incsrc "path2/.././path2/./test.asm" 9 | -------------------------------------------------------------------------------- /tests/freespacealign.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07606 5C 00 80 91 3 | ;`07FD7 0A 4 | ;`87FF8 5 | ;`53 54 41 52 03 00 FC FF 6 | ;`AF 56 34 12 7 | ;`FFFFF 00 8 | org $00F606 9 | autoclean JML Mymain 10 | freecode align 11 | Mymain: 12 | LDA $123456 -------------------------------------------------------------------------------- /tests/mappers.asm: -------------------------------------------------------------------------------- 1 | ;`00 00 00 00 40 41 42 2 | ;`warnWmapper_already_set 3 | ;`warnWmapper_already_set 4 | lorom 5 | org $008004 6 | db $40 7 | 8 | hirom 9 | org $C00005 10 | db $41 11 | 12 | norom 13 | org $000006 14 | db $42 15 | -------------------------------------------------------------------------------- /tests/bank_shorthand.asm: -------------------------------------------------------------------------------- 1 | ;`A9 00 00 A9 03 00 A9 02 00 2 | org $008000 3 | main: 4 | lda #<:main 5 | lda #<:test_label 6 | lda #bank(other_test) 7 | 8 | base $038000 9 | test_label: 10 | 11 | base $028000 12 | other_test: 13 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9.0) 2 | cmake_policy(SET CMP0091 NEW) 3 | 4 | project(Asar) 5 | 6 | option(ASAR_USE_SANITIZER "Build Asar with ASan" OFF) 7 | 8 | add_subdirectory(asar) 9 | 10 | add_subdirectory(asar-tests) 11 | -------------------------------------------------------------------------------- /tests/functest2.asm: -------------------------------------------------------------------------------- 1 | ;`10 2 | ;`10 3 | 4 | ; define 5 | !AAA = 4 6 | 7 | ; macro 8 | macro Undi() 9 | db test(!AAA) 10 | endmacro 11 | 12 | ; function 13 | function test(n) = 4*n 14 | 15 | org $8000 16 | 17 | main: 18 | db test(!AAA) 19 | %Undi() 20 | -------------------------------------------------------------------------------- /tests/0x.asm: -------------------------------------------------------------------------------- 1 | ;`errEunknown_operator 2 | ;`errEunknown_operator 3 | ;`errEunknown_operator 4 | 5 | ; RPG Hacker: Is this text actually supposed to fail, or was 0x supported by Asar at some point? 6 | org $008000 7 | AND #~0x8000 8 | db ~0x80 9 | db 0x80 10 | db 010 -------------------------------------------------------------------------------- /tests/archswitch.asm: -------------------------------------------------------------------------------- 1 | ;`EA 00 01 EA 00 01 EA 00 01 2 | org $008000 3 | arch 65816 : NOP 4 | arch spc700 : NOP 5 | arch superfx : NOP 6 | arch 65816 : NOP 7 | arch spc700 : NOP 8 | arch superfx : NOP 9 | arch 65816 : NOP 10 | arch spc700 : NOP 11 | arch superfx : NOP -------------------------------------------------------------------------------- /cmake/mingw-x64.cmake: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # mingw x64 toolchain 3 | #----------------------------------------------------------- 4 | set(MINGW_TYPE "x86_64-w64-mingw32") 5 | include(${CMAKE_CURRENT_LIST_DIR}/_mingw-common.cmake) 6 | -------------------------------------------------------------------------------- /cmake/mingw-x86.cmake: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # mingw x86 toolchain 3 | #----------------------------------------------------------- 4 | set(MINGW_TYPE "i686-w64-mingw32") 5 | include(${CMAKE_CURRENT_LIST_DIR}/_mingw-common.cmake) 6 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | ABS=$(pwd) 2 | mkdir tests_tmp_dll tests_tmp_app 3 | $ABS/asar-tests/asar-dll-test $ABS/asar/lib/libasar.so $ABS/tests $ABS/dummy_rom.sfc $ABS/tests_tmp_dll 4 | $ABS/asar-tests/asar-app-test $ABS/asar/bin/asar $ABS/tests $ABS/dummy_rom.sfc $ABS/tests_tmp_app 5 | -------------------------------------------------------------------------------- /tests/functest1.asm: -------------------------------------------------------------------------------- 1 | ;`08 2 | ;`08 3 | 4 | ; define 5 | !AAA = 4 6 | 7 | ; macro 8 | macro Undi() 9 | db test(!AAA) 10 | endmacro 11 | 12 | ; function 13 | function test(n) = 2*n 14 | 15 | org $8000 16 | 17 | main: 18 | db test(!AAA) 19 | %Undi() 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/fill.asm: -------------------------------------------------------------------------------- 1 | ;`12 12 12 12 2 | ;`34 12 34 12 34 12 34 12 3 | ;`56 34 12 56 34 12 56 34 12 56 34 12 4 | ;`78 56 34 12 78 56 34 12 78 56 34 12 78 56 34 12 5 | org $008000 6 | fillbyte $12 : fill 4 7 | fillword $1234 : fill 8 8 | filllong $123456 : fill 12 9 | filldword $12345678 : fill 16 -------------------------------------------------------------------------------- /tests/datasize.asm: -------------------------------------------------------------------------------- 1 | ;`A9 03 00 A9 F3 7F A9 09 00 00 00 02 2 | ;`warnWdatasize_last_label 3 | ;`warnWdatasize_exceeds_size 4 | org $008000 5 | main: 6 | 7 | lda #datasize(my_table) ;3 8 | lda #datasize(other_label) ;0xFFFFFF 9 | lda #datasize(main) ;9 10 | 11 | 12 | my_table: 13 | db $00, $00, $02 14 | other_label: 15 | -------------------------------------------------------------------------------- /tests/optimization-warn.asm: -------------------------------------------------------------------------------- 1 | ;`ad 12 00 af 13 00 01 af 56 34 12 20 12 00 2 | ;`warnWoptimization_settings 3 | ;`warnWoptimization_settings 4 | ;`warnWoptimization_settings 5 | org $8000 6 | lbl = $12 7 | lbl2 = $010013 8 | lbl3 = $123456 9 | lda lbl 10 | lda lbl2 11 | lda lbl3 12 | ; this does not give the warning 13 | jsr lbl 14 | -------------------------------------------------------------------------------- /tests/sfxfreespace.asm: -------------------------------------------------------------------------------- 1 | ;`#2 2 | ;`80000 53 54 41 52 03 00 FC FF 3 | ;`EA EA EA EA 4 | ;`1FFFFF 00 5 | 6 | sfxrom 7 | ; slight hack to do different stuff on 2nd invocation (sfxrom doesn't have autoexpanding) 8 | if canread1($8000) 9 | freecode cleaned 10 | NOP #4 11 | else 12 | org $3fffff 13 | db $00 14 | endif 15 | -------------------------------------------------------------------------------- /tests/prot.asm: -------------------------------------------------------------------------------- 1 | ;`+ #2 2 | ;`07606 22 15 80 90 3 | ;`07FD7 0A 4 | ;`80000 5 | ;`53 54 41 52 0D 00 F2 FF 6 | ;`50 52 4F 54 03 1E 80 90 7 | ;`53 54 4F 50 00 8 | ;`EA 9 | ;`53 54 41 52 00 00 FF FF 10 | ;`EA 11 | ;`FFFFF 00 12 | org $00F606 13 | autoclean JSL a 14 | 15 | freecode 16 | prot b 17 | a: 18 | NOP 19 | 20 | freedata 21 | b: 22 | NOP -------------------------------------------------------------------------------- /tests/read.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`00000 01 79 7A 9C 9F 00 42 46 9C 0C 42 3 | ;`80000 4 | ;must be in "patch-to-smw" mode since Asar considers it to read outside the ROM otherwise 5 | 6 | check title "SUPER MARIOWORLD " 7 | 8 | org $008000 9 | db $01 10 | db read1($008000)+1 11 | dw read2($008000)+2 12 | dl read3($008001)+3 13 | dd read4($008003)+4 14 | -------------------------------------------------------------------------------- /run_tests.bat: -------------------------------------------------------------------------------- 1 | set ABS=%~dp0 2 | set ABS=%ABS:~0,-1% 3 | set CONFIG=Release 4 | mkdir tests_tmp_dll tests_tmp_app 5 | %ABS%\asar-tests\%CONFIG%\asar-dll-test.exe %ABS%\asar\lib\%CONFIG%\asar.dll %ABS%\tests %ABS%\dummy_rom.sfc %ABS%\tests_tmp_dll 6 | %ABS%\asar-tests\%CONFIG%\asar-app-test.exe %ABS%\asar\bin\%CONFIG%\asar.exe %ABS%\tests %ABS%\dummy_rom.sfc %ABS%\tests_tmp_app 7 | @pause -------------------------------------------------------------------------------- /tests/spcblock.asm: -------------------------------------------------------------------------------- 1 | ;`A9 AA 2 | ;`03 00 00 60 3 | ;`8F 44 33 4 | ;`06 00 00 50 5 | ;`5F 03 50 6 | ;`8F 22 11 7 | ;`00 00 00 50 8 | ;`A9 BB 9 | 10 | org $008000 11 | 12 | lda #$AA 13 | 14 | spcblock $6000 15 | mov $33,#$44 16 | endspcblock 17 | 18 | spcblock $5000 19 | start: 20 | jmp lab 21 | lab: 22 | mov $11,#$22 23 | endspcblock execute start 24 | 25 | lda #$BB 26 | -------------------------------------------------------------------------------- /tests/spcsynonyms.asm: -------------------------------------------------------------------------------- 1 | ;`63 12 FD 63 12 FA 2 | ;`63 12 F7 63 12 F4 3 | ;`EA 12 60 EA 12 60 4 | ;`EA 12 60 EA 12 60 5 | ;`EA 12 60 EA 12 60 6 | warnings disable Wfeature_deprecated 7 | arch spc700-raw 8 | org 0 9 | L: 10 | bbs1 $12.3,L : bbs $12.3,L 11 | bbs1 $12.3,L : bbs3 $12,L 12 | not1 c,$12.3 : not1 $12.3 13 | not1 c,$12.3 : not3 c,$12 14 | not1 c,$12.3 : not3 $12 15 | -------------------------------------------------------------------------------- /dummy_rom.asm: -------------------------------------------------------------------------------- 1 | ; Dummy ROM to use for Asar's test suite 2 | 3 | org $008000 4 | ; 7 bytes from SMW, used in tests/read.asm 5 | db $78,$9C,$00,$42,$9C,$0C,$42 6 | 7 | org $00FFC0 8 | ; to make expecttitle not fail 9 | db "SUPER MARIOWORLD " 10 | db $20 ; lorom 11 | 12 | org $00FFD7 13 | db $0A ; mark the rom as 512 kb 14 | 15 | org $0FFFFF 16 | db $00 ; to pad the ROM to 512 kb -------------------------------------------------------------------------------- /src/asar/interface-shared.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // This function should only be called inside assembleblock.cpp. 4 | void print(const char * str); 5 | 6 | // This function should only be called inside errors.cpp. 7 | void error_interface(int errid, int whichpass, const char * e_); 8 | 9 | // This function should only be called inside warnings.cpp. 10 | void warn(int errid, const char * e); 11 | -------------------------------------------------------------------------------- /tests/protonbankstart.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07FD7 0A 3 | ;`80000 53 54 41 52 2F 75 D0 8A 4 | ;`87FF8 53 54 41 52 94 13 6B EC 5 | ;`88000 50 52 4F 54 03 08 80 90 53 54 4F 50 6 | ;`FFFFF 00 7 | freedata cleaned 8 | A: 9 | !i = 0 10 | while !i < 30000 11 | db 0 12 | !i #= !i+1 13 | endwhile 14 | 15 | freedata cleaned 16 | prot A 17 | !j = 0 18 | while !j < 5000 19 | db 0 20 | !j #= !j+1 21 | endwhile 22 | -------------------------------------------------------------------------------- /src/asar/lib/libasar.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=@ASAR_PKGCONF_LIBDIR@ 4 | includedir=@ASAR_PKGCONF_INCLUDEDIR@ 5 | 6 | Name: lib@ASAR_PROJECT_NAME@ 7 | URL: https://github.com/RPGHacker/asar 8 | Description: SNES assembler 9 | Version: @ASAR_API_VERSION@ 10 | 11 | Libs: -L${libdir} -l@ASAR_PROJECT_NAME@ 12 | Cflags: -I${includedir}/@ASAR_PROJECT_NAME@ 13 | -------------------------------------------------------------------------------- /tests/datasize_freespace.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`A9 03 00 A9 F4 7F 22 08 80 90 3 | ;`80000 53 54 41 52 02 00 FD FF 00 00 02 4 | ;`FFFFF 00 5 | ;`warnWdatasize_last_label 6 | ;`warnWdatasize_exceeds_size 7 | 8 | org $008000 9 | main: 10 | 11 | lda #datasize(my_table) ;3 12 | lda #datasize(other_label) ;0xFFFFFF 13 | autoclean jsl my_table 14 | freecode 15 | my_table: 16 | db $00, $00, $02 17 | other_label: 18 | -------------------------------------------------------------------------------- /tests/nestedpushpcfreespace.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07FD7 0A 3 | ;`80000 4 | ;`53 54 41 52 05 00 FA FF 5 | ;`01 02 03 04 05 06 6 | ;`53 54 41 52 02 00 FD FF 7 | ;`07 08 09 8 | ;`53 54 41 52 02 00 FD FF 9 | ;`0A 0B 0C 10 | ;`FFFFF 00 11 | 12 | freedata cleaned 13 | db 1,2,3 14 | 15 | pushpc 16 | freedata cleaned 17 | db 7,8,9 18 | pullpc 19 | 20 | db 4,5,6 21 | Label: 22 | 23 | freedata cleaned 24 | db 10,11,12 -------------------------------------------------------------------------------- /tests/nesteddefines.asm: -------------------------------------------------------------------------------- 1 | ;`10 20 30 40 FF 2 | ;`50 60 70 80 FF 3 | 4 | org $008000 5 | 6 | !mycompletedefine = $10,$20,$30,$40,$ 7 | 8 | !first = complete 9 | !second = de 10 | !third = ne 11 | 12 | !fourth = !{second}fi!{third} 13 | 14 | !fifth = ur 15 | 16 | !combined = !{my!{first}!{fo!{fifth}th}}FF 17 | 18 | db !combined 19 | 20 | !{my!{first}!{fo!{fifth}th}} = $50,$60,$70,$80,$ 21 | 22 | db !combined 23 | -------------------------------------------------------------------------------- /src/asar/arch-shared.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Should only be called inside assembleblock.cpp 4 | void asinit_65816(); 5 | bool asblock_65816(char** word, int numwords, bool fake, int& outlen); 6 | void asend_65816(); 7 | void asinit_spc700(); 8 | bool asblock_spc700(char** word, int numwords); 9 | void asend_spc700(); 10 | void asinit_superfx(); 11 | bool asblock_superfx(char** word, int numwords); 12 | void asend_superfx(); 13 | -------------------------------------------------------------------------------- /tests/builtindefinespass.asm: -------------------------------------------------------------------------------- 1 | ;`01 03 06 07 2 | 3 | org $008000 4 | 5 | if stringsequal("!assembler", "asar") 6 | db $01 7 | else 8 | db $02 9 | endif 10 | 11 | if stringsequalnocase("!assembler", "ASAR") 12 | db $03 13 | else 14 | db $04 15 | endif 16 | 17 | if stringsequal("!assembler", "xkas") 18 | db $05 19 | else 20 | db $06 21 | endif 22 | 23 | if !assembler_ver >= 10602 24 | db $07 25 | else 26 | db $08 27 | endif 28 | -------------------------------------------------------------------------------- /src/asar/platform/file-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "libstr.h" 4 | 5 | bool file_exists(const char * filename); 6 | bool path_is_absolute(const char* path); 7 | char get_native_path_separator(); 8 | bool check_is_regular_file(const char* path); 9 | 10 | string dir(char const *name); 11 | string create_combined_path(const char* path1, const char* path2); 12 | string normalize_path(const char* path); 13 | string get_base_name(char const *name); 14 | -------------------------------------------------------------------------------- /tests/pushpullns.asm: -------------------------------------------------------------------------------- 1 | ;`20 00 80 20 00 80 20 0C 80 20 03 80 20 0C 80 20 03 80 2 | 3 | org $008000 4 | namespace test 5 | namespace nested on 6 | namespace test2 7 | test3: 8 | pushns 9 | namespace asdf 10 | jsr test_test2_test3 11 | test3: 12 | test2: 13 | pullns 14 | jsr test3 15 | jsr asdf_test3 16 | jsr asdf_test2 17 | namespace asdf 18 | test3: 19 | namespace nested off 20 | namespace off 21 | jsr test_test2_asdf_test3 22 | jsr asdf_test3 23 | pushns 24 | pullns 25 | -------------------------------------------------------------------------------- /tests/fastrom.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`01 3 | ;`80 FE 4 | ;`4C 01 80 5 | ;`5C 01 80 00 6 | ;` 7 | ;`07FD7 0A 8 | ;`80000 9 | ;`53 54 41 52 0D 00 F2 FF 10 | ;`50 52 4F 54 03 11 | ;`15 80 90 12 | ;`53 54 4F 50 00 13 | ;`EA 14 | ;`FFFFF 00 15 | ;`warnWfeature_deprecated 16 | 17 | fastrom ; this is a null operation. it gives too much trouble. 18 | 19 | org $8000 20 | db $01 21 | 22 | Test: 23 | BRA Test 24 | JMP Test 25 | JML Test 26 | 27 | freecode cleaned 28 | prot A 29 | A: 30 | NOP 31 | -------------------------------------------------------------------------------- /tests/bigincbin.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07606 5C 15 80 90 3 | ;`07FD7 0A 4 | ;` 5 | ;`80000 6 | ;`53 54 41 52 10 00 EF FF 7 | ;`50 52 4F 54 03 00 80 91 8 | ;`53 54 4F 50 00 9 | ;`AF 00 80 91 10 | ;` 11 | ;`87FF8 12 | ;`53 54 41 52 FF FF 00 00 13 | ;`88000 89 AB 14 | ;`8FFFE 12 34 15 | ;`90000 56 78 16 | ;`97FFE CD EF 17 | ;`FFFFF 00 18 | ;`warnWfeature_deprecated 19 | 20 | org $00F606 21 | autoclean JML Mymain 22 | freecode 23 | prot Derp 24 | Mymain: 25 | incbin "data/64kb.bin" -> Derp 26 | LDA Derp 27 | -------------------------------------------------------------------------------- /tests/macronoarg.asm: -------------------------------------------------------------------------------- 1 | ;`EA 2 | macro a() 3 | org $008000 4 | NOP 5 | endmacro 6 | 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 11 | 12 | %a() -------------------------------------------------------------------------------- /license-wtfpl.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /src/asar/platform/generic/file-helpers-generic.cpp: -------------------------------------------------------------------------------- 1 | #include "platform/file-helpers.h" 2 | #include 3 | 4 | bool file_exists(const char * filename) 5 | { 6 | FILE * f = fopen(filename, "rb"); 7 | if (f) fclose(f); 8 | return f; 9 | } 10 | 11 | bool path_is_absolute(const char* path) 12 | { 13 | return ('/' == path[0]); 14 | } 15 | 16 | char get_native_path_separator() 17 | { 18 | return '/'; 19 | } 20 | 21 | bool check_is_regular_file(const char* path) 22 | { 23 | // no really universal way to check this 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /tests/multiprot.asm: -------------------------------------------------------------------------------- 1 | ;`+ #2 2 | ;`07606 22 20 80 90 3 | ;`07FD7 0A 4 | ;`80000 5 | ;`53 54 41 52 18 00 E7 FF 6 | ;`50 52 4F 54 06 29 80 90 32 80 90 7 | ;`50 52 4F 54 03 3C 80 90 8 | ;`53 54 4F 50 00 9 | ;`EA 10 | ;`53 54 41 52 00 00 FF FF 11 | ;`EA 12 | ;`53 54 41 52 01 00 FE FF 13 | ;`EA EA 14 | ;`53 54 41 52 02 00 FD FF 15 | ;`EA EA EA 16 | ;`FFFFF 00 17 | org $00F606 18 | autoclean JSL root 19 | 20 | freecode 21 | prot a,b 22 | prot c 23 | root: 24 | NOP 25 | 26 | freedata 27 | a: 28 | NOP 29 | 30 | freedata 31 | b: 32 | NOP #2 33 | 34 | freedata 35 | c: 36 | NOP #3 -------------------------------------------------------------------------------- /src/asar/asar_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // for int64_t 3 | 4 | void initmathcore(); 5 | void deinitmathcore(); 6 | 7 | int64_t getnum(const char * str); 8 | int64_t getnum64(const char * str); 9 | double getnumdouble(const char * str); 10 | 11 | void createuserfunc(const char * name, const char * arguments, const char * content); 12 | 13 | void closecachedfiles(); 14 | 15 | double math(const char * mystr); 16 | 17 | extern bool foundlabel; 18 | extern bool foundlabel_static; 19 | extern bool forwardlabel; 20 | 21 | extern bool math_pri; 22 | extern bool math_round; 23 | -------------------------------------------------------------------------------- /tests/autoclean_2freecode_to_1freecode.asm: -------------------------------------------------------------------------------- 1 | ;`+ #2 2 | ;`000000 3 | ;`22 08 80 90 4 | ;`22 09 80 90 5 | ;`07FD7 0A 6 | ;`80000 7 | ;`53 54 41 52 01 00 FE FF 6B 6B 8 | ;`FFFFF 00 9 | 10 | 11 | org $008000 12 | 13 | if read1($008000) != $22 14 | 15 | ; print "first run" 16 | 17 | autoclean jsl hijack1 18 | autoclean jsl hijack2 19 | 20 | freecode 21 | hijack1: 22 | rtl 23 | 24 | freecode 25 | hijack2: 26 | rtl 27 | 28 | else 29 | 30 | ; print "second run" 31 | 32 | autoclean jsl hijack1 33 | autoclean jsl hijack2 34 | 35 | freecode 36 | hijack1: 37 | rtl 38 | hijack2: 39 | rtl 40 | 41 | endif 42 | -------------------------------------------------------------------------------- /docs/shared/common.js: -------------------------------------------------------------------------------- 1 | hljs.configure( 2 | { 3 | tabReplace: ' ', 4 | } 5 | ); 6 | hljs.highlightAll(); 7 | 8 | hljsAsar.init(); 9 | 10 | function toggle_visibility(id) 11 | { 12 | var e =document.getElementById(id); 13 | var label = document.getElementById(id.concat("-toggle")); 14 | 15 | if(e.style.display == 'none') 16 | { 17 | label.innerHTML = label.innerHTML.replace("[+] Expand","[-] Collapse"); 18 | e.style.display = 'block'; 19 | } 20 | else 21 | { 22 | label.innerHTML = label.innerHTML.replace("[-] Collapse","[+] Expand"); 23 | e.style.display = 'none'; 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/autoclean_twice.asm: -------------------------------------------------------------------------------- 1 | ;`+ #2 2 | ;`000000 3 | ;`22 09 80 90 4 | ;`22 13 80 90 5 | ;`000020 6 | ;`22 09 80 90 7 | ;`07FD7 0A 8 | ;`080000 53 54 41 52 01 00 FE FF 01 01 53 54 41 52 01 00 9 | ;`080010 FE FF 02 02 10 | ;`FFFFF 00 11 | 12 | ;print "previous test1: $",hex(read3($008000+1)) 13 | ;print "previous test2: $",hex(read3($008004+1)) 14 | ;print "new test1: $",hex(test1) 15 | ;print "new test2: $",hex(test2) 16 | 17 | org $008000 18 | autoclean JSL test1 19 | autoclean JSL test2 20 | 21 | freecode 22 | db 1 23 | test1: db 1 24 | 25 | org $008020 26 | autoclean JSL test1 27 | 28 | freecode 29 | db 2 30 | test2: db 2 31 | -------------------------------------------------------------------------------- /src/asar/platform/linux/file-helpers-linux.cpp: -------------------------------------------------------------------------------- 1 | #include "platform/file-helpers.h" 2 | #include 3 | 4 | bool file_exists(const char * filename) 5 | { 6 | struct stat st; 7 | return (!stat(filename, &st)); 8 | } 9 | 10 | bool path_is_absolute(const char* path) 11 | { 12 | return ('/' == path[0]); 13 | } 14 | 15 | char get_native_path_separator() 16 | { 17 | return '/'; 18 | } 19 | 20 | bool check_is_regular_file(const char* path) 21 | { 22 | struct stat finfo; 23 | if (stat(path, &finfo) == 0) 24 | { 25 | // either regular file or symlink 26 | if (finfo.st_mode & (S_IFREG | S_IFLNK)) 27 | return true; 28 | } 29 | return false; 30 | } 31 | -------------------------------------------------------------------------------- /src/asar/libcon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | void libcon_init(int argc, char * argv[], const char * usage); 3 | const char * libcon_require(const char * desc); 4 | const char * libcon_require_filename(const char * desc); 5 | const char * libcon_optional(const char * desc, const char * defval); 6 | const char * libcon_optional_filename(const char * desc, const char * defval); 7 | const char * libcon_option(); 8 | const char * libcon_option_value(); 9 | const char * libcon_question(const char * desc, const char * defval); 10 | bool libcon_question_bool(const char * desc, bool defval); 11 | void libcon_end(); 12 | void libcon_badusage(); 13 | void libcon_pause(); 14 | extern bool libcon_interactive; 15 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Asar 5 | 6 | 7 | 8 |

Asar

9 |
10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/xkasemu.asm: -------------------------------------------------------------------------------- 1 | ;`warnWfeature_deprecated 2 | ;`warnWfeature_deprecated 3 | ;`warnWfeature_deprecated 4 | ;`warnWfeature_deprecated 5 | ;`warnWfeature_deprecated 6 | ;`warnWfeature_deprecated 7 | ;`warnWfeature_deprecated 8 | ;`warnWfeature_deprecated 9 | ;`warnWfeature_deprecated 10 | ;`warnWfeature_deprecated 11 | ;`warnWfeature_deprecated 12 | ;`warnWfeature_deprecated 13 | ;`warnWfeature_deprecated 14 | ;`warnWfeature_deprecated 15 | ;`warnWfeature_deprecated 16 | ;`53 54 41 52 17 | ;`21 61 18 | ;`BF 0A 80 00 19 | ;` 20 | ;`01 02 03 03 21 | 22 | ;@xkas 23 | org $008000 24 | 25 | db "STAR" 26 | 27 | db "!a" 28 | 29 | LDA derp,x 30 | derp: 31 | 32 | incbin .\include\dummy.asm 33 | 34 | rep -1 : db 0 35 | rep 0 : db 1 36 | rep 1 : db 2 37 | rep 2 : db 3 38 | -------------------------------------------------------------------------------- /src/asar/macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void startmacro(const char * line); 4 | void tomacro(const char * line); 5 | void endmacro(bool insert); 6 | void callmacro(const char * data); 7 | string replace_macro_args(const char* line); 8 | 9 | extern int macrorecursion; 10 | extern int calledmacros; 11 | extern int reallycalledmacros; 12 | extern bool inmacro; 13 | extern int numvarargs; 14 | 15 | struct macrodata 16 | { 17 | autoarray lines; 18 | int numlines; 19 | int startline; 20 | const char * fname; 21 | const char * const* arguments; 22 | int numargs; 23 | bool variadic; 24 | }; 25 | 26 | extern assocarr macros; 27 | extern macrodata* current_macro; 28 | extern const char* const* current_macro_args; 29 | extern int current_macro_numargs; 30 | -------------------------------------------------------------------------------- /tests/sa1bankswitch.asm: -------------------------------------------------------------------------------- 1 | ;`000000 10 2 | ;`080000 11 3 | ;`100000 12 4 | ;`180000 13 5 | ;`200000 14 6 | ;`280000 15 7 | ;`300000 16 8 | ;`380000 17 9 | ;`400000 1C 10 | ;`480000 1D 11 | ;`500000 1E 12 | ;`580000 1F 13 | ;`600000 18 14 | ;`680000 19 15 | ;`700000 1A 16 | ;`780000 1B 17 | 18 | sa1rom 0,1,2,3 19 | org $008000 20 | db $10 21 | org $108000 22 | db $11 23 | org $208000 24 | db $12 25 | org $308000 26 | db $13 27 | org $808000 28 | db $14 29 | org $908000 30 | db $15 31 | org $A08000 32 | db $16 33 | org $B08000 34 | db $17 35 | 36 | sa1rom 6,7,4,5 37 | org $008000 38 | db $18 39 | org $108000 40 | db $19 41 | org $208000 42 | db $1A 43 | org $308000 44 | db $1B 45 | org $808000 46 | db $1C 47 | org $908000 48 | db $1D 49 | org $A08000 50 | db $1E 51 | org $B08000 52 | db $1F 53 | 54 | sa1rom 0,1,2,3 55 | -------------------------------------------------------------------------------- /tests/tablefiles.asm: -------------------------------------------------------------------------------- 1 | ;`78 56 34 12 2 | ;`78 56 56 34 34 12 12 00 3 | ;`78 56 34 56 34 12 34 12 00 12 00 00 4 | ;`78 56 34 12 56 34 12 00 34 12 00 00 12 00 00 00 5 | ;` 6 | ;`10 20 30 10 7 | ;`10 20 30 10 8 | ;`11 21 31 11 9 | ;`42 42 10 | ;`43 43 11 | 12 | org $008000 13 | 14 | incsrc "data/table.asm" 15 | db "ABCD" 16 | dw "ABCD" 17 | dl "ABCD" 18 | dd "ABCD" 19 | 20 | 't' = $10 21 | 'e' = $20 22 | 's' = $30 23 | 24 | db "test" 25 | db 't','e','s','t' 26 | db 't'+1,'e'+1,'s'+1,'t'+1 27 | 28 | ''' = $42 ; Comment after actual line 29 | ; ''' = $44 ; This line is a comment and should be ignored 30 | db "'" 31 | db ''' 32 | 33 | ';' = $43 ; Comment after actual line 34 | ; ';' = $45 ; This line is a comment and should be ignored 35 | db ";" 36 | db ';' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # SNES ROMs 35 | *.smc 36 | *.sfc 37 | 38 | # Visual Studio build files and CMAKE build files on Windows 39 | asar/ 40 | src/asar/res/windows/asar_lib.aps 41 | !src/asar 42 | CMakefiles/ 43 | asar-tests/ 44 | .vs 45 | ALL_BUILD.* 46 | ZERO_CHECK.* 47 | cmake_install.cmake 48 | Project.sln 49 | CMakeCache.txt 50 | 51 | # Test folders 52 | tests_tmp_dll/ 53 | tests_tmp_app/ 54 | *.aps 55 | 56 | # Just because I like building into /bin... 57 | /bin 58 | -------------------------------------------------------------------------------- /tests/forloop.asm: -------------------------------------------------------------------------------- 1 | ;`00 01 02 03 04 2 | ;`01 01 01 01 01 3 | ;`42 4 | ;`00 03 00 04 00 05 01 03 01 04 01 05 02 03 02 04 02 05 5 | ;`0a 0b 6 | ;`11 11 11 7 | ;`69 00 69 01 6a 00 6a 01 8 | ;`00 01 02 00 01 02 00 01 02 9 | 10 | org $8000 11 | 12 | !i = $42 13 | 14 | for i = 0..5 15 | db !i 16 | endfor 17 | 18 | for i = 0..5 : db 1 : endfor 19 | 20 | for i = 3..2 21 | dw $dead 22 | endfor 23 | 24 | db !i 25 | 26 | for i = 0..3 27 | for j = 3..6 28 | db !i,!j 29 | endfor 30 | endfor 31 | 32 | if 1 33 | for i = 10..12 34 | db !i 35 | endfor 36 | endif 37 | 38 | if 0 39 | for i = 12..14 40 | db !i 41 | endfor 42 | endif 43 | 44 | if 1 45 | for i = 0..3 : db $11 : endfor 46 | endif 47 | 48 | for i = $69..$6b 49 | !j = 0 50 | while !j < 2 51 | db !i,!j 52 | !j #= !j+1 53 | endwhile 54 | endfor 55 | 56 | for i = 0..3 57 | for i = 0..3 58 | db !i 59 | endfor 60 | endfor 61 | -------------------------------------------------------------------------------- /src/asar/res/windows/asar_lib.rc: -------------------------------------------------------------------------------- 1 | 1 VERSIONINFO 2 | FILEVERSION 1,9,1,0 3 | PRODUCTVERSION 1,9,1,0 4 | { 5 | BLOCK "StringFileInfo" 6 | { 7 | BLOCK "040904b0" // en-US with UTF-8 8 | { 9 | VALUE "CompanyName", "Asar devs\0" 10 | VALUE "FileDescription", "SNES assembler\0" 11 | // explorer apparently always shows the file version with the numbers, but product version with text? 12 | VALUE "FileVersion", "v1.91\0" 13 | // apparently this is required? 14 | VALUE "InternalName", "asar\0" 15 | VALUE "OriginalFilename", "asar.dll\0" 16 | VALUE "ProductName", "Asar\0" 17 | VALUE "ProductVersion", "v1.91\0" 18 | } 19 | } 20 | BLOCK "VarFileInfo" 21 | { 22 | VALUE "Translation", 0x409, 1200 // en-US with UTF-8 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/labels_static_fail.asm: -------------------------------------------------------------------------------- 1 | ;`errElabel_in_conditional 2 | ;`errElabel_in_conditional 3 | ;`errElabel_in_conditional 4 | ;`errElabel_in_conditional 5 | ;`errElabel_in_conditional 6 | ;`errElabel_cross_assignment 7 | ;`errEdefine_label_math 8 | org $008000 9 | ANonStaticLabel: 10 | 11 | struct TestStruct 12 | .first: skip 1 13 | .second: skip 1 14 | .count: skip 1 15 | endstruct 16 | 17 | struct NewStruct extends TestStruct 18 | .new: skip 1 19 | endstruct 20 | 21 | 22 | if ANonStaticLabel == $008000 23 | ; This should fail 24 | endif 25 | 26 | if TestStruct.count == 2 27 | ; This should fail 28 | endif 29 | 30 | if TestStruct[0].count == 2 31 | ; This should fail 32 | endif 33 | 34 | if TestStruct.NewStruct.new == 3 35 | ; This should fail 36 | endif 37 | 38 | if TestStruct.NewStruct[0].new == 3 39 | ; This should fail 40 | endif 41 | 42 | ANewLabel = ANonStaticLabel 43 | 44 | !adefine #= ANonStaticLabel 45 | -------------------------------------------------------------------------------- /.github/workflows/docs-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy manual to Pages 2 | on: 3 | push: 4 | branches: 5 | - asar_19 6 | tags: 7 | - '*' 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write # To push a branch 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - name: Deploy GitHub Pages 19 | run: | 20 | git worktree add gh-pages gh-pages 21 | git config user.name "Deploy from CI" 22 | git config user.email "" 23 | cd gh-pages 24 | # Delete the ref to avoid keeping history. 25 | git update-ref -d refs/heads/gh-pages 26 | rm -rf ${{ github.ref_name }} 27 | cp -r ../docs ${{ github.ref_name }} 28 | git add . 29 | git commit -m "Deploy $GITHUB_SHA to gh-pages" 30 | git push --force --set-upstream origin gh-pages 31 | -------------------------------------------------------------------------------- /tests/global_label_success.asm: -------------------------------------------------------------------------------- 1 | ;`ea 5c 08 80 00 ea ea ea ea ea ea 22 00 80 00 22 2 | ;`01 80 00 22 05 80 00 22 06 80 00 22 07 80 00 22 3 | ;`08 80 00 22 09 80 00 22 0a 80 00 22 0b 80 00 4 | 5 | lorom 6 | org $008000 7 | 8 | namespace nested on 9 | global label1: : nop 10 | namespace main 11 | label1: 12 | jml label2 13 | namespace second 14 | label2: : nop 15 | namespace third 16 | label3: : nop 17 | .sublabel : nop 18 | global label2: : nop 19 | .sublabel : nop 20 | global #label3: : nop 21 | ..sublabel 22 | namespace off 23 | namespace off 24 | namespace off 25 | namespace nested off 26 | jsl label1 27 | jsl main_label1 28 | jsl main_second_label2 29 | jsl main_second_third_label3 30 | jsl main_second_third_label3_sublabel 31 | jsl label2 32 | jsl main_second_third_label2_sublabel 33 | jsl label3 34 | jsl main_second_third_label2_sublabel_sublabel -------------------------------------------------------------------------------- /src/asar/res/windows/asar.rc: -------------------------------------------------------------------------------- 1 | 1 ICON DISCARDABLE "asar.ico" 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION 1,9,1,0 5 | PRODUCTVERSION 1,9,1,0 6 | { 7 | BLOCK "StringFileInfo" 8 | { 9 | BLOCK "040904b0" // en-US with UTF-8 10 | { 11 | VALUE "CompanyName", "Asar devs\0" 12 | VALUE "FileDescription", "SNES assembler\0" 13 | // explorer apparently always shows the file version with the numbers, but product version with text? 14 | VALUE "FileVersion", "v1.91\0" 15 | // apparently this is required? 16 | VALUE "InternalName", "asar\0" 17 | VALUE "OriginalFilename", "asar.exe\0" 18 | VALUE "ProductName", "Asar\0" 19 | VALUE "ProductVersion", "v1.91\0" 20 | } 21 | } 22 | BLOCK "VarFileInfo" 23 | { 24 | VALUE "Translation", 0x409, 1200 // en-US with UTF-8 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/asar/std-includes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // RPG Hacker: Some standard headers unfortunately like to 4 | // spew loads of warnings on some platforms, and since this 5 | // is kinda annoying, let's wrap the headers in here so 6 | // that we can easily disable certain warnings via pragmas. 7 | 8 | #if defined(_MSC_VER) 9 | # pragma warning(push) 10 | # pragma warning(disable : 4514) 11 | # pragma warning(disable : 4577) 12 | # pragma warning(disable : 4668) 13 | # pragma warning(disable : 4987) 14 | #endif 15 | 16 | #include //placement new 17 | #include //malloc, realloc, free 18 | #include //strcmp, memmove 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | inline char * duplicate_string(const char * str) 25 | { 26 | char * a = (char*)malloc(sizeof(char)*(strlen(str) + 1)); 27 | strcpy(a, str); 28 | return a; 29 | } 30 | 31 | #if defined(_MSC_VER) 32 | # pragma warning(pop) 33 | #endif 34 | -------------------------------------------------------------------------------- /tests/variadic_syntax.asm: -------------------------------------------------------------------------------- 1 | ;`01 01 01 FF FF 05 01 01 FF FF 01 02 03 04 05 06 07 FF FF 02 03 04 05 06 07 01 01 02 03 2 | ;`warnWfeature_deprecated 3 | ;`warnWfeature_deprecated 4 | lorom 5 | org $008000 6 | 7 | !a = 0 8 | macro asd(...) 9 | db sizeof(...), <...[0]>, ; Intentionally uses deprecated syntax, to make sure it still works 10 | endmacro 11 | 12 | macro sorry(...) 13 | !a = 0 14 | while !a < sizeof(...) 15 | db <...[!a]> 16 | !a #= !a+1 17 | endwhile 18 | endmacro 19 | 20 | macro sorry2(asd, ...) 21 | !a = 0 22 | db <...[0]> 23 | while !a < sizeof(...)-1 24 | db <...[!a+1]> 25 | !a #= !a+1 26 | endwhile 27 | db 28 | endmacro 29 | 30 | macro optional(required, ...) 31 | db 32 | if sizeof(...) > 0 33 | db <...[0]> 34 | endif 35 | endmacro 36 | 37 | %asd(1) 38 | db $FF, $FF 39 | 40 | %asd(1,2,3,4,5) 41 | db $FF, $FF 42 | 43 | %sorry(1,2,3,4,5,6,7) 44 | db $FF, $FF 45 | %sorry2(1,2,3,4,5,6,7) 46 | 47 | %optional(1) 48 | %optional(2, 3) 49 | -------------------------------------------------------------------------------- /src/asar/libmisc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | inline int min(int val) 3 | { 4 | return val; 5 | } 6 | 7 | template inline int min(int arg1, const Args&... args)//if this is functional programming, I don't want to know more about it. 8 | { 9 | int i=min(args...); 10 | if (arg1 inline int posmin(int arg1, const Args&... args) 20 | { 21 | int i=posmin(args...); 22 | if (arg1>=0 && arg1 struct forceconst { enum { value = N }; }; 27 | #define forceconst(n) (forceconst::value) 28 | 29 | //from nall, license: ISC 30 | //round up to next highest single bit: 31 | //round(15) == 16, round(16) == 16, round(17) == 32 32 | inline unsigned bitround(unsigned x) 33 | { 34 | if ((x & (x - 1)) == 0) return x; 35 | while (x & (x - 1)) x &= x - 1; 36 | return x << 1; 37 | } 38 | -------------------------------------------------------------------------------- /tests/sa1altmapper.asm: -------------------------------------------------------------------------------- 1 | ;`000000 69 13 37 2 | ;`080000 42 99 12 3 | ;`100000 53 54 41 4 | ;`180000 41 54 53 5 | ;`200000 12 34 56 6 | ;`280000 68 01 11 7 | ;`300000 99 99 99 8 | ;`380000 01 23 45 9 | ;` 10 | ;`400000 00 FF 00 11 | ;`480000 69 96 69 12 | ;`500000 42 42 42 13 | ;`580000 DE DE DE 14 | ;`600000 DE AD 55 15 | ;`680000 BE EF 55 16 | ;`700000 A1 CA 40 17 | ;`780000 BE DE AD 18 | 19 | fullsa1rom 20 | 21 | org $008000 22 | db $69,$13,$37 23 | org $108000 24 | db $42,$99,$12 25 | org $208000 26 | db $53,$54,$41 27 | org $308000 28 | db $41,$54,$53 29 | org $808000 30 | db $12,$34,$56 31 | org $908000 32 | db $68,$01,$11 33 | org $A08000 34 | db $99,$99,$99 35 | org $B08000 36 | db $01,$23,$45 37 | 38 | org $C00000 39 | db $00,$FF,$00 40 | org $C80000 41 | db $69,$96,$69 42 | org $D00000 43 | db $42,$42,$42 44 | org $D80000 45 | db $DE,$DE,$DE 46 | org $E00000 47 | db $DE,$AD,$55 48 | org $E80000 49 | db $BE,$EF,$55 50 | org $F00000 51 | db $A1,$CA,$40 52 | org $F80000 53 | db $BE,$DE,$AD -------------------------------------------------------------------------------- /cmake/_mingw-common.cmake: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # mingw toolchain common 3 | #----------------------------------------------------------- 4 | 5 | set(MINGW ON) 6 | set(WIN32 ON) 7 | set(CMAKE_SYSTEM_NAME Windows) 8 | set(TOOL_PREFIX "${MINGW_TYPE}-") 9 | 10 | if(CLANG) 11 | set(CMAKE_C_COMPILER "${TOOL_PREFIX}clang") 12 | set(CMAKE_CXX_COMPILER "${TOOL_PREFIX}clang++") 13 | else(CLANG) 14 | set(CMAKE_C_COMPILER "${TOOL_PREFIX}gcc") 15 | set(CMAKE_CXX_COMPILER "${TOOL_PREFIX}g++") 16 | endif(CLANG) 17 | 18 | set(CMAKE_RC_COMPILER ${TOOL_PREFIX}windres) 19 | set(CMAKE_RC_COMPILE_OBJECT 20 | " -O coff -i -o ") 21 | #set(CMAKE_LINKER "${TOOL_PREFIX}g++") 22 | #set(CMAKE_AR "${TOOL_PREFIX}ar") 23 | 24 | set(CMAKE_FIND_ROOT_PATH "/usr/${MINGW_TYPE}/") 25 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 27 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 28 | 29 | -------------------------------------------------------------------------------- /tests/macrolabels.asm: -------------------------------------------------------------------------------- 1 | ;`00 00 2 | ;`00 00 3 | ;`02 80 00 4 | ;`02 80 00 5 | ;`00 80 00 6 | ;`04 80 00 7 | ;`1B 80 00 8 | ;`16 80 00 9 | ;`00 90 00 10 | ;`00 00 11 | ;`00 00 12 | ;`00 00 13 | ;`1D 80 00 14 | ;`1D 80 00 15 | ;`04 80 00 16 | ;`04 80 00 17 | ;`3C 61 3E 18 | 19 | org $008000 20 | Main: 21 | macro macro_with_labels() 22 | ?MacroMain: 23 | db $00,$00 24 | ?.MacroSub: 25 | db $00,$00 26 | ?-: 27 | #InMacro: 28 | #.InMacroSub: 29 | dl ?.MacroSub 30 | dl ?MacroMain_MacroSub 31 | dl - 32 | dl ?- 33 | dl + 34 | dl ?+ 35 | ?+: 36 | ?MacroAssignment = $009000 37 | dl ?MacroAssignment 38 | endmacro 39 | 40 | -: 41 | %macro_with_labels() 42 | db $00,$00 43 | +: 44 | db $00,$00 45 | 46 | .Sub: 47 | db $00,$00 48 | 49 | dl .Sub 50 | dl Main_Sub 51 | dl InMacro 52 | dl Main_InMacroSub ; Note that this is not InMacro_InMacroSub 53 | 54 | ; not exactly a test for macro labels, but close enough 55 | db "" ; macro argument outside macro - should be left unexpanded 56 | 57 | -------------------------------------------------------------------------------- /tests/namespaces.asm: -------------------------------------------------------------------------------- 1 | ;`00 00 2 | ;`00 00 3 | ;`00 00 4 | ;`00 00 5 | ;`06 80 00 6 | ;`04 80 00 7 | ;`06 80 00 8 | ;`02 80 00 9 | ;`04 80 00 10 | ;`06 80 00 11 | ;`00 80 00 12 | ;`02 80 00 13 | ;`04 80 00 14 | ;`06 80 00 15 | ;`00 00 16 | ;`26 80 00 17 | 18 | 19 | 20 | org $008000 21 | 22 | 23 | namespace nested on 24 | 25 | 26 | Main: 27 | db $00,$00 28 | 29 | namespace First 30 | { 31 | Main: 32 | db $00,$00 33 | 34 | namespace Second 35 | { 36 | Main: 37 | db $00,$00 38 | 39 | namespace Third 40 | { 41 | Main: 42 | db $00,$00 43 | 44 | dl Main 45 | 46 | } 47 | namespace off 48 | 49 | dl Main 50 | dl Third_Main 51 | } 52 | namespace off 53 | 54 | dl Main 55 | dl Second_Main 56 | dl Second_Third_Main 57 | } 58 | namespace off 59 | 60 | dl Main 61 | dl First_Main 62 | dl First_Second_Main 63 | dl First_Second_Third_Main 64 | 65 | 66 | namespace nested off 67 | 68 | 69 | namespace First 70 | { 71 | namespace Second 72 | { 73 | namespace Third 74 | { 75 | Main2: 76 | db $00,$00 77 | 78 | } 79 | } 80 | } 81 | namespace off 82 | 83 | 84 | dl Third_Main2 85 | -------------------------------------------------------------------------------- /src/asar/lib/JoinPaths.cmake: -------------------------------------------------------------------------------- 1 | # This module provides a function for joining paths 2 | # known from most languages 3 | # 4 | # SPDX-License-Identifier: (MIT OR CC0-1.0) 5 | # Copyright 2020 Jan Tojnar 6 | # https://github.com/jtojnar/cmake-snips 7 | # 8 | # Modelled after Python’s os.path.join 9 | # https://docs.python.org/3.7/library/os.path.html#os.path.join 10 | # Windows not supported 11 | function(join_paths joined_path first_path_segment) 12 | set(temp_path "${first_path_segment}") 13 | foreach(current_segment IN LISTS ARGN) 14 | if(NOT ("${current_segment}" STREQUAL "")) 15 | string(REGEX REPLACE "^${CMAKE_INSTALL_PREFIX}/?" "" new_segment "${current_segment}") 16 | if(NOT ("${new_segment}" STREQUAL "")) 17 | if(NOT IS_ABSOLUTE "${current_segment}" OR NOT "${current_segment}" MATCHES "^${new_segment}$") 18 | set(temp_path "${temp_path}/${new_segment}") 19 | else() 20 | set(temp_path "${current_segment}") 21 | endif() 22 | endif() 23 | endif() 24 | endforeach() 25 | set(${joined_path} "${temp_path}" PARENT_SCOPE) 26 | endfunction() 27 | -------------------------------------------------------------------------------- /src/asar/platform/windows/file-helpers-win32.cpp: -------------------------------------------------------------------------------- 1 | // RPG Hacker: We can't include that here, because it leads to crazy 2 | // errors in windows.h - probably related to our string class?!? 3 | //#include "platform/file-helpers.h" 4 | 5 | #if defined(_MSC_VER) 6 | # pragma warning(push) 7 | # pragma warning(disable : 4668) 8 | # pragma warning(disable : 4987) 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | #if defined(_MSC_VER) 15 | # pragma warning(pop) 16 | #endif 17 | 18 | #include 19 | 20 | #include "../file-helpers.h" 21 | 22 | bool file_exists(const char * filename) 23 | { 24 | return (GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES); 25 | } 26 | 27 | bool path_is_absolute(const char* path) 28 | { 29 | return ((isalpha(path[0]) && 30 | (':' == path[1]) && (('\\' == path[2]) || ('/' == path[2]))) /* drive letter + root, e.g. C:\dir or C:/dir */ 31 | || ('\\' == path[0]) || ('/' == path[0])); /* just root, e.g. \dir or /dir */ 32 | } 33 | 34 | char get_native_path_separator() 35 | { 36 | return '\\'; 37 | } 38 | 39 | bool check_is_regular_file(const char* path) 40 | { 41 | return !(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY); 42 | } 43 | -------------------------------------------------------------------------------- /tests/escaping.asm: -------------------------------------------------------------------------------- 1 | ;`01 02 03 04 00 01 02 03 04 05 06 01 2 | ;`01 02 03 04 10 01 02 03 04 11 12 3 | ;`01 02 03 04 01 02 03 04 4 | ;`10 01 02 03 04 11 12 01 02 03 04 5 | ;`01 02 03 04 10 01 02 03 04 11 12 6 | ;`20 01 02 20 20 20 03 04 20 10 01 02 03 04 11 12 7 | ;P>The values of !a and !b are 10 and 20. 8 | ;P>The values of !a and !b are 10 and 20. 9 | macro do_stuff_1(stuff_1, stuff_2) 10 | 11 | 12 | endmacro 13 | 14 | macro do_stuff_2( stuff_1 , stuff_2 ) 15 | db 16 | db 17 | endmacro 18 | 19 | 'a' = $01 20 | 'b' = $02 21 | 'c' = $03 22 | 'd' = $04 23 | 'e' = $05 24 | 'f' = $06 25 | ' ' = $20 26 | 27 | org $008000 28 | %do_stuff_1("db ""abcd"",$00,""abcdef""", "db 'a'") 29 | %do_stuff_2("""abcd""", "$10,""abcd"",$11,$12") 30 | %do_stuff_2("""abcd""", """abcd""") 31 | %do_stuff_2("$10,""abcd"",$11,$12", """abcd""") 32 | %do_stuff_2("""abcd""", 33 | "$10,""abcd"",$11,$12") 34 | %do_stuff_2( """ ab cd """ , ; A lot of intentional spaces here. 35 | "$10,""abcd"",$11,$12" ) 36 | 37 | !a = 10 38 | !b = 20 39 | 40 | print "The values of \!a and \!b are !a and !b." 41 | 42 | macro do_print() 43 | print "The values of \!a and \!b are !a and !b." 44 | endmacro 45 | 46 | %do_print() 47 | -------------------------------------------------------------------------------- /tests/variadic_errors.asm: -------------------------------------------------------------------------------- 1 | ;`errEvararg_must_be_last 2 | ;`errEinvalid_macro_param_name 3 | ;`warnWfeature_deprecated 4 | ;`errEunclosed_vararg 5 | ;`errEinvalid_vararg 6 | ;`errEinvalid_vararg 7 | ;`errEvararg_out_of_bounds 8 | ;`errEvararg_out_of_bounds 9 | ;`errEmacro_wrong_min_params 10 | ;`errEvararg_out_of_bounds 11 | ;`errEmacro_wrong_min_params 12 | ;`errEvararg_sizeof_nomacro 13 | ;`errEmacro_not_varadic 14 | 15 | 16 | 17 | lorom 18 | org $008000 19 | 20 | !a = 0 21 | macro asd(..., dfg) 22 | db sizeof(...), <0>, 23 | endmacro 24 | 25 | macro sorry(...) 26 | db <...[-1]> 27 | endmacro 28 | 29 | macro sorry2(asd, ...) 30 | db <...[10]> 31 | endmacro 32 | 33 | macro normal() 34 | db sizeof(...) 35 | endmacro 36 | 37 | macro sorry3(asd, ...) 38 | db 0 39 | endmacro 40 | 41 | %asd(1, 2) 42 | db $FF, $FF 43 | db sizeof(...) 44 | %normal() 45 | 46 | %sorry(1,2,3,4,5,6,7) 47 | db $FF, $FF 48 | %sorry2(1,2,3,4,5,6,7) 49 | %sorry2() 50 | %sorry2(0) 51 | %sorry3() 52 | 53 | 54 | macro deprecated(...) 55 | db <0> 56 | endmacro 57 | 58 | macro unclosed(...) 59 | db <...[0> 60 | endmacro 61 | 62 | macro invalid(named, ...) 63 | db <...[named]> 64 | endmacro 65 | 66 | macro invalid_2(named) 67 | db <...[named]> 68 | endmacro 69 | 70 | %deprecated($01) 71 | %unclosed($01) 72 | %invalid($01, $01) 73 | %invalid_2($01) 74 | -------------------------------------------------------------------------------- /tests/advanced-prints.asm: -------------------------------------------------------------------------------- 1 | ;P>This is a simple print. 2 | ;P>This is a print with some functions: 01010101, 0B, 0123 3 | ;`errEerror_command 4 | ;`warnWwarn_command 5 | ;`errEassertion_failed 6 | ;E>This is a user error. 7 | ;W>This is a user warning. 8 | ;E>Oh no, 0 is not equal to 1! 9 | ;`errEerror_command 10 | ;`warnWwarn_command 11 | ;`errEassertion_failed 12 | ;E>This is a user error with some functions: 01010101, 0B, 0123 13 | ;W>This is a user warning with some functions: 01010101, 0B, 0123 14 | ;E>Oh no, 0 is not equal to select(1, 1, 0)! So here's some functions: 01010101, 0B, 0123 15 | ;`errEerror_command 16 | ;`warnWwarn_command 17 | ;`errEassertion_failed 18 | 19 | print "This is a simple print." 20 | print "This is a print with some functions: ",bin(%01010101, 8),", ",hex($0B, 2),", ",dec(0123, 4) 21 | 22 | error 23 | warn 24 | assert 0 == 1 25 | 26 | error "This is a user error." 27 | warn "This is a user warning." 28 | assert 0 == 1, "Oh no, 0 is not equal to 1!" 29 | 30 | error "This is a user error with some functions: ",bin(%01010101, 8),", ",hex($0B, 2),", ",dec(0123, 4) 31 | warn "This is a user warning with some functions: ",bin(%01010101, 8),", ",hex($0B, 2),", ",dec(0123, 4) 32 | assert 0 == select(1, 1, 0), "Oh no, 0 is not equal to select(1, 1, 0)! So here's some functions: ",bin(%01010101, 8),", ",hex($0B, 2),", ",dec(0123, 4) -------------------------------------------------------------------------------- /src/asar/dll_helper.h: -------------------------------------------------------------------------------- 1 | #if defined(_WIN32) 2 | 3 | #include 4 | 5 | struct function_pointer_wrapper/*have this struct at global level*/ 6 | { 7 | static void (*callback)(void *); 8 | static void __stdcall execute(void *parameter) { return callback(parameter); } 9 | }; 10 | 11 | void (*function_pointer_wrapper::callback)(void *) = nullptr; 12 | 13 | template 14 | bool run_as_fiber(functor &&callback) { 15 | struct fiber_wrapper { 16 | functor &callback; 17 | void *original; 18 | bool result; 19 | 20 | void execute() { 21 | result = callback(); 22 | SwitchToFiber(original); 23 | } 24 | 25 | } wrapper{callback, nullptr, false}; 26 | 27 | function_pointer_wrapper::callback = [](void *parameter){ 28 | reinterpret_cast(parameter)->execute(); 29 | }; 30 | auto fiber = CreateFiberEx(4*1024*1024, 8*1024*1024, 0, &function_pointer_wrapper::execute, &wrapper); 31 | 32 | if (!fiber) { 33 | return callback(); 34 | } 35 | 36 | void* main_thread = ConvertThreadToFiber(nullptr); 37 | if (!main_thread && GetLastError() != ERROR_ALREADY_FIBER) { 38 | return callback(); 39 | } 40 | wrapper.original = GetCurrentFiber(); 41 | SwitchToFiber(fiber); 42 | DeleteFiber(fiber); 43 | if (main_thread) { 44 | ConvertFiberToThread(); 45 | } 46 | return wrapper.result; 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /generate_release_zip.py: -------------------------------------------------------------------------------- 1 | import zipfile 2 | import sys 3 | import urllib.request 4 | import os 5 | 6 | if len(sys.argv) != 2: 7 | print("Usage: {} version_number".format(sys.argv[0])) 8 | sys.exit(1) 9 | 10 | branch_name = 'asar_19' 11 | 12 | zipf = zipfile.ZipFile("asar"+sys.argv[1]+".zip", 'x', compression=zipfile.ZIP_DEFLATED) 13 | 14 | build_server_prefix = lambda f, n, b: f"https://random.muncher.se/ftp/asar/windows/{branch_name}/{b}/build/asar/{f}/MinSizeRel/{n}" 15 | with urllib.request.urlopen(build_server_prefix("bin", "asar.exe", "win64")) as resp: 16 | exe_data = resp.read() 17 | with urllib.request.urlopen(build_server_prefix("lib", "asar.dll", "win32")) as resp: 18 | dll_data = resp.read() 19 | 20 | zipf.writestr("asar.exe", exe_data) 21 | zipf.writestr("dll/asar.dll", dll_data) 22 | 23 | for (dirpath, dirnames, filenames) in os.walk("docs"): 24 | for x in filenames: 25 | zipf.write(dirpath + "/" + x) 26 | 27 | for (dirpath, dirnames, filenames) in os.walk("ext"): 28 | for x in filenames: 29 | zipf.write(dirpath + "/" + x) 30 | 31 | zipf.write("README.txt") 32 | zipf.write("LICENSE") 33 | zipf.write("license-gpl.txt") 34 | zipf.write("license-lgpl.txt") 35 | zipf.write("license-wtfpl.txt") 36 | 37 | for (dirpath, dirnames, filenames) in os.walk("src/asar-dll-bindings"): 38 | for x in filenames: 39 | zipf.write(dirpath+"/"+x, dirpath.replace("src/asar-dll-bindings", "dll/bindings")+"/"+x) 40 | -------------------------------------------------------------------------------- /src/asar/addr2line.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | ////////////////////////////////////////////////////////////////////////// 4 | // Class to store address-to-line mappings for richer symbolic information 5 | // 6 | // During assembly, included files and information about generated asm 7 | // should be added to this, and then read back during symbol file 8 | // generation 9 | 10 | #include "autoarray.h" 11 | #include "libstr.h" 12 | #include 13 | 14 | class AddressToLineMapping 15 | { 16 | public: 17 | 18 | struct AddrToLineInfo 19 | { 20 | int fileIdx; 21 | int line; 22 | int addr; 23 | }; 24 | 25 | // resets the mapping to initial state 26 | void reset(); 27 | 28 | // Adds information of what source file and line number an output rom address is at 29 | void includeMapping(const char* filename, int line, int addr); 30 | 31 | struct FileInfo 32 | { 33 | string filename; 34 | uint32_t fileCrc; 35 | }; 36 | const autoarray& getFileList() const { return m_fileList; } 37 | const autoarray& getAddrToLineInfo() const { return m_addrToLineInfo; } 38 | 39 | private: 40 | 41 | // Helper to add file to list, and get the index of that file 42 | int getFileIndex(const char* filename); 43 | 44 | autoarray m_fileList; 45 | // parallel list of crcs of the filenames in fileList, to speed up lookups 46 | autoarray m_filenameCrcs; 47 | 48 | 49 | autoarray m_addrToLineInfo; 50 | }; 51 | 52 | extern AddressToLineMapping addressToLineMapping; 53 | -------------------------------------------------------------------------------- /tests/v160features.asm: -------------------------------------------------------------------------------- 1 | ;`00 2 | ;`EE 3 | ;`10 4 | ;`01 5 | ;`01 6 | ;`DD 7 | ;`01 8 | ;`00 9 | ;`00 10 | ;`01 11 | ;`78 12 | ;`21 61 13 | ;`5C 78 14 | ;`01 90 02 15 | ;`00 80 00 16 | ;`01 90 02 17 | ;`8a 18 | ;`ac 19 | 20 | asar 1.60 21 | 22 | lorom 23 | org $008000 24 | 25 | 26 | base $029001 27 | 28 | BaseTest1: 29 | 30 | pushbase 31 | 32 | base off 33 | 34 | BaseTest2: 35 | 36 | pullbase 37 | 38 | BaseTest3: 39 | 40 | base off 41 | 42 | 43 | ; This file should not exist 44 | if getfilestatus("bogusfilename.lol") == 0 45 | db $FF 46 | endif 47 | 48 | db canreadfile1("bogusfilename.lol", 0) 49 | db readfile1("bogusfilename.lol", 0, $EE) 50 | 51 | ; This file SHOULD exist 52 | if getfilestatus("data/filename with spaces.bin") == 0 53 | db filesize("data/filename with spaces.bin") 54 | endif 55 | 56 | db canreadfile1("data/filename with spaces.bin", 0) 57 | db readfile1("data/filename with spaces.bin", 0, $EE) 58 | db readfile1("data/filename with spaces.bin", 20, $DD) 59 | 60 | !testdefine = "poop" 61 | db defined("testdefine") 62 | db defined("shouldntexist") 63 | 64 | undef "testdefine" 65 | 66 | db defined("testdefine") 67 | 68 | !testdefine = "oppo" 69 | 70 | db defined("testdefine") 71 | 72 | 73 | !a = "x" 74 | 75 | db "!a" 76 | db "\!a" 77 | db "\\!a" 78 | 79 | dl BaseTest1 80 | dl BaseTest2 81 | dl BaseTest3 82 | 83 | function readfile1_incremented(filename, pos) = readfile1(filename, pos)+1 84 | 85 | db readfile1_incremented("data/64kb.bin",0) 86 | db readfile1_incremented("data/64kb.bin",1) 87 | -------------------------------------------------------------------------------- /tests/labels_static_pass.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`56 78 3 | ;`BA 4 | ;`BA 5 | ;`EE EE EE 6 | ;`03 7 | ;`42 8 | ;`007FFE EE EE 9 | ;P>Test passed. (1) 10 | ;P>Test passed. (2) 11 | ;P>Test passed. (3) 12 | ;P>Test passed. (4) 13 | ;P>Test passed. (5) 14 | 15 | org $008000 16 | AStaticLabel = 10 17 | 18 | struct TestStruct $000000 19 | .first: skip 1 20 | .second: skip 1 21 | .count: skip 1 22 | endstruct 23 | 24 | struct NewStruct extends TestStruct 25 | .new: skip 1 26 | endstruct 27 | 28 | if AStaticLabel == 10 29 | print "Test passed. (1)" 30 | endif 31 | 32 | if TestStruct.count == 2 33 | print "Test passed. (2)" 34 | endif 35 | 36 | if TestStruct[0].count == 2 37 | print "Test passed. (3)" 38 | endif 39 | 40 | if TestStruct.NewStruct.new == 3 41 | print "Test passed. (4)" 42 | endif 43 | 44 | if TestStruct.NewStruct[0].new == 3 45 | print "Test passed. (5)" 46 | endif 47 | 48 | ; RPG Hacker: Not that this made much sense, but, you know... we can now. 49 | IncbinStart = $008000 50 | IncbinEnd = $008002 51 | 52 | incbin "data/64kb.bin":IncbinStart..IncbinEnd 53 | 54 | FunStuff = $BA 55 | 'a' = FunStuff 56 | 57 | OtherFunStuff = FunStuff 58 | 59 | db 'a' 60 | db OtherFunStuff 61 | 62 | FillByte = $EE 63 | FillCount = 3 64 | 65 | fillbyte FillByte 66 | fill FillCount 67 | 68 | !adefine #= FillCount 69 | 70 | db !adefine 71 | 72 | ArgID = 2 73 | 74 | macro in_macro(...) 75 | db <...[ArgID]> 76 | endmacro 77 | 78 | %in_macro($40, $41, $42) 79 | 80 | 81 | org $00FFFE 82 | 83 | padbyte FillByte 84 | pad $018000 85 | 86 | -------------------------------------------------------------------------------- /tests/std.asm: -------------------------------------------------------------------------------- 1 | ;`B0 A0 90 80 70 60 50 40 30 20 10 F0 E0 2 | 3 | incsrc "std/test.asm" 4 | 5 | org $008000 6 | 7 | if defined("stdincluded") 8 | db $B0 9 | else 10 | error "Define 'stdincluded' not found! (Check std includes)." 11 | endif 12 | 13 | if defined("stddefined") 14 | db $A0 15 | else 16 | error "Define 'stddefined' not found! (Check std defines)." 17 | endif 18 | 19 | if defined("stddefined2") 20 | db $90 21 | else 22 | error "Define 'stddefined2' not found! (Check std defines)." 23 | endif 24 | 25 | if defined("stddefined3") 26 | db $80 27 | else 28 | error "Define 'stddefined3' not found! (Check std defines)." 29 | endif 30 | 31 | if defined("stddefined4") 32 | db $70 33 | else 34 | error "Define 'stddefined4' not found! (Check std defines)." 35 | endif 36 | 37 | if defined("stddefined5") 38 | ; There is no space here on purpose so that we can test if quoted defines work properly 39 | db!stddefined5 40 | else 41 | error "Define 'stddefined5' not found! (Check std defines)." 42 | endif 43 | 44 | if defined("cmddefined") 45 | db $30 46 | else 47 | error "Define 'cmddefined' not found! (Check command line defines)." 48 | endif 49 | 50 | if defined("cmddefined2") 51 | db $20 52 | else 53 | error "Define 'cmddefined2' not found! (Check command line defines)." 54 | endif 55 | 56 | if defined("cmddefined3") 57 | ; There is no space here on purpose so that we can test if quoted defines work properly 58 | db!cmddefined3 59 | else 60 | error "Define 'cmddefined3' not found! (Check command line defines)." 61 | endif 62 | -------------------------------------------------------------------------------- /src/asar/virtualfile.h: -------------------------------------------------------------------------------- 1 | #if !defined(ASAR_VIRTUALFILE_H) 2 | #define ASAR_VIRTUALFILE_H 3 | 4 | #include "autoarray.h" 5 | #include "assocarr.h" 6 | #include "libstr.h" 7 | 8 | // RPG Hacker: A virtual file system which can work with physical files 9 | // as well as in-memory files. 10 | 11 | typedef void* virtual_file_handle; 12 | static const virtual_file_handle INVALID_VIRTUAL_FILE_HANDLE = nullptr; 13 | 14 | enum virtual_file_error 15 | { 16 | vfe_none, 17 | 18 | vfe_doesnt_exist, 19 | vfe_access_denied, 20 | vfe_not_regular_file, 21 | vfe_unknown, 22 | 23 | vfe_num_errors 24 | }; 25 | 26 | struct memory_buffer 27 | { 28 | const void* data; 29 | size_t length; 30 | }; 31 | 32 | class virtual_filesystem 33 | { 34 | public: 35 | void initialize(const char** include_paths, size_t num_include_paths); 36 | void destroy(); 37 | 38 | virtual_file_handle open_file(const char* path, const char* base_path); 39 | void close_file(virtual_file_handle file_handle); 40 | 41 | size_t read_file(virtual_file_handle file_handle, void* out_buffer, size_t pos, size_t num_bytes); 42 | 43 | size_t get_file_size(virtual_file_handle file_handle); 44 | 45 | bool is_path_absolute(const char* path); 46 | 47 | string create_absolute_path(const char* base, const char* target); 48 | 49 | void add_memory_file(const char* name, const void* buffer, size_t length); 50 | 51 | inline virtual_file_error get_last_error() 52 | { 53 | return m_last_error; 54 | } 55 | 56 | private: 57 | enum virtual_file_type 58 | { 59 | vft_physical_file, 60 | vft_memory_file 61 | }; 62 | 63 | virtual_file_type get_file_type_from_path(const char* path); 64 | 65 | assocarr m_memory_files; 66 | autoarray m_include_paths; 67 | virtual_file_error m_last_error; 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/asar/addr2line.cpp: -------------------------------------------------------------------------------- 1 | #include "addr2line.h" 2 | #include "asar.h" 3 | #include "crc32.h" 4 | #include "libstr.h" 5 | #include 6 | 7 | ////////////////////////////////////////////////////////////////////////// 8 | // Class to store address-to-line mappings for richer symbolic information 9 | // 10 | // During assembly, included files and information about generated asm 11 | // should be added to this, and then read back during symbol file 12 | // generation 13 | 14 | void AddressToLineMapping::reset() 15 | { 16 | m_fileList.reset(); 17 | m_filenameCrcs.reset(); 18 | m_addrToLineInfo.reset(); 19 | } 20 | 21 | // Adds information of what source file and line number an output rom address is at 22 | void AddressToLineMapping::includeMapping(const char* filename, int line, int addr) 23 | { 24 | AddrToLineInfo newInfo; 25 | newInfo.fileIdx = getFileIndex(filename); 26 | newInfo.line = line; 27 | newInfo.addr = addr; 28 | 29 | m_addrToLineInfo.append(newInfo); 30 | } 31 | 32 | // Helper to add file to list, and get the index of that file 33 | int AddressToLineMapping::getFileIndex(const char* filename) 34 | { 35 | // check if the file exists first 36 | uint32_t filenameCrc = crc32((const uint8_t*)filename, (unsigned int)strlen(filename)); 37 | for (int i = 0; i < m_filenameCrcs.count; ++i) 38 | { 39 | if (m_filenameCrcs[i] == filenameCrc) 40 | { 41 | return i; 42 | } 43 | } 44 | 45 | // file doesn't exist, so start tracking it 46 | char* data = nullptr; 47 | int len = 0; 48 | uint32_t fileCrc = 0; 49 | if (readfile(filename, "", &data, &len)) 50 | { 51 | fileCrc = crc32((const uint8_t*)data, (unsigned int)len); 52 | } 53 | free(data); 54 | 55 | m_fileList.append({ string(filename), fileCrc }); 56 | m_filenameCrcs.append(filenameCrc); 57 | 58 | return m_fileList.count - 1; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/structs.asm: -------------------------------------------------------------------------------- 1 | ;`AD 07 00 AD 02 00 AD 02 00 DC 00 00 DC 07 00 A9 40 00 8D 25 43 2 | ;`02 03 05 07 03 05 02 05 3 | ;`warnWfeature_deprecated 4 | ;`warnWfeature_deprecated 5 | ;`02 40 6 | ;`00 40 7 | ;`04 40 8 | 9 | struct struct_without_org $4000 10 | .first: skip 2 11 | .second: skip 2 12 | endstruct 13 | 14 | org $008000 15 | 16 | struct test $0000 17 | .size: skip 2 18 | endstruct 19 | 20 | struct test2 extends test 21 | .lol: skip 3 22 | endstruct 23 | 24 | struct test3 extends test 25 | .lol: skip 5 26 | endstruct 27 | 28 | struct test2 extends struct_without_org 29 | endstruct 30 | 31 | optimize address default 32 | optimize dp none 33 | 34 | lda test[1].size 35 | ;lda test.size 36 | lda test.test2.lol 37 | lda test.test3.lol 38 | 39 | jmp [$0000] 40 | jmp [test[1].size] 41 | 42 | 43 | struct sprite $009E 44 | .number: skip 12 45 | .yspeed: skip 12 46 | .xspeed: skip 12 47 | .state: skip 12 48 | skip 3+2+2+3 ;get to next table 49 | .y_pos: skip 12 50 | .x_pos: skip 12 51 | ;etc 52 | endstruct 53 | 54 | 55 | struct DMA $4300 56 | .control: skip 1 57 | .destination: skip 1 58 | .source 59 | .source_word: 60 | .source_word_low: skip 1 61 | .source_word_high: skip 1 62 | .source_bank: skip 1 63 | .size: 64 | .size_low: skip 1 65 | .size_high: skip 1 66 | endstruct align $10 67 | 68 | lda #$0040 69 | sta DMA[2].size 70 | 71 | db sizeof(test) 72 | db sizeof(test.test2) 73 | db sizeof(test.test3) 74 | db objectsize(test) 75 | db objectsize(test.test2) 76 | db objectsize(test.test3) 77 | ; RPG Hacker: Don't quite get why these throw each warning twice. 78 | ; Seems a bit buggy, but I couldn't find anything out, and really don't care enough. 79 | db sizeof("test") 80 | db objectsize("test.test3") 81 | 82 | dw struct_without_org.second 83 | dw struct_without_org 84 | dw struct_without_org.test2 85 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Asar Readme 2 | =========== 3 | 4 | If you just want to apply patches, double click asar.exe and Asar will ask you 5 | for the patch file and the ROM. You can also pass arguments on the command 6 | line, they are documented in the manual (see below). 7 | 8 | Writing Patches 9 | --------------- 10 | 11 | For a detailed guide on all commands supported by Asar, see the included manual 12 | (also available on-line at https://rpghacker.github.io/asar/asar_19/manual/ ). 13 | 14 | Another thing that may be helpful when writing patches is syntax highlighting. 15 | Currently asar includes syntax definitions for Notepad++ and Sublime Text. 16 | 17 | To install it for Notepad++, go to Language -> Define your language..., then 18 | click Import near the top and navigate to Asar's directory -> ext -> 19 | notepad-plus-plus, and open syntax-highlighting.xml. 20 | For Sublime Text, go to Preferences -> Browse Packages... -> User, and copy 21 | ext/sublime-text/65c816.sublime-syntax there. 22 | 23 | History 24 | ------- 25 | 26 | For a detailed changelog, please see the included changelog (or on-line at 27 | https://rpghacker.github.io/asar/asar_19/changelog/ ). 28 | 29 | Bug reports 30 | ----------- 31 | 32 | First, make sure the bug is in Asar, not the patch you are applying. When you 33 | are sure that the problem is in Asar: 34 | 35 | Asar's issue tracking is at https://github.com/RPGHacker/asar/issues . If you 36 | find a bug, please first check that the issue hasn't been reported yet, and then 37 | create a new issue, detailing what happens, what you expected to happen, and the 38 | patch you are trying to apply. 39 | 40 | If you don't have a GitHub account, you can also tell someone about the bug on 41 | Discord (in the #asm channel on SMWC, or #asar on SnesLab) or the SMW Central 42 | forums (in Asar's thread, https://smwc.me/t/51349 ). 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Asar is licensed under GNU Lesser General Public License, version 3 or later. The full legal text 2 | can be found in license-lgpl.txt, but it is also allowed to obey the following rules instead if 3 | you prefer that (legalese is complicated): 4 | 5 | If you don't want to redistribute it or distribute modifications (aka you only want it for personal 6 | use), you may do whatever you want with it. The author of Asar claims no copyright over input, 7 | binary output or textual output (including error messages) generated by Asar. 8 | 9 | If you do want to redistribute it, you must obey the LGPL. This means the following: 10 | - You must credit the author. Don't claim it as your own. You may modify it and take credit for your 11 | modifications, but the author (Alcaro) must be credited for the original software. 12 | - You must make it possible to replace your copy of Asar with another version, if anyone wants that. 13 | If you're using one of the dynamic libraries, you must either keep it as a separate file and allow 14 | anyone who wants to replace it, or you must offer all source codes and related files that are 15 | required to rebuild your tool to anyone who asks. If Asar is linked statically into the same 16 | program, only the latter option is possible. 17 | - If you modify this software, it must clearly be labeled as a modification, and you must provide 18 | full source code to anyone who asks. 19 | 20 | However, as a special exception, the DLL interface files (dll/asardll.h and dll/asardll.cpp) 21 | are licensed under the WTFPL (version 2 or later), which much means you may use them for 22 | anything you want. You don't need to make them upgradable, you don't need to credit the 23 | author, and you don't need to release any source codes. Note that this does not apply to the DLLs 24 | themselves, or anything compiled into a library. -------------------------------------------------------------------------------- /tests/elseif.asm: -------------------------------------------------------------------------------- 1 | ;`01 2 | 3 | !count = 0 4 | 5 | !y = "!count #= !count+1" 6 | !n = "db 0" 7 | 8 | org $008000 9 | 10 | if 1 11 | if 1 12 | !y 13 | elseif 1 14 | !n 15 | else 16 | !n 17 | endif 18 | 19 | 20 | if 0 21 | !n 22 | elseif 1 23 | !y 24 | else 25 | !n 26 | endif 27 | 28 | 29 | if 1 30 | !y 31 | elseif 0 32 | !n 33 | else 34 | !n 35 | endif 36 | 37 | 38 | if 0 39 | !n 40 | elseif 0 41 | !n 42 | else 43 | !y 44 | endif 45 | elseif 1 46 | !n 47 | else 48 | !n 49 | endif 50 | 51 | 52 | 53 | if 0 54 | !n 55 | elseif 1 56 | if 1 57 | !y 58 | elseif 1 59 | !n 60 | else 61 | !n 62 | endif 63 | 64 | 65 | if 0 66 | !n 67 | elseif 1 68 | !y 69 | else 70 | !n 71 | endif 72 | 73 | 74 | if 1 75 | !y 76 | elseif 0 77 | !n 78 | else 79 | !n 80 | endif 81 | 82 | 83 | if 0 84 | !n 85 | elseif 0 86 | !n 87 | else 88 | !y 89 | endif 90 | else 91 | !n 92 | endif 93 | 94 | 95 | 96 | if 1 97 | if 1 98 | !y 99 | elseif 1 100 | !n 101 | else 102 | !n 103 | endif 104 | 105 | 106 | if 0 107 | !n 108 | elseif 1 109 | !y 110 | else 111 | !n 112 | endif 113 | 114 | 115 | if 1 116 | !y 117 | elseif 0 118 | !n 119 | else 120 | !n 121 | endif 122 | 123 | 124 | if 0 125 | !n 126 | elseif 0 127 | !n 128 | else 129 | !y 130 | endif 131 | elseif 0 132 | !n 133 | else 134 | !n 135 | endif 136 | 137 | 138 | 139 | if 0 140 | !n 141 | elseif 0 142 | !n 143 | else 144 | if 1 145 | !y 146 | elseif 1 147 | !n 148 | else 149 | !n 150 | endif 151 | 152 | 153 | if 0 154 | !n 155 | elseif 1 156 | !y 157 | else 158 | !n 159 | endif 160 | 161 | 162 | if 1 163 | !y 164 | elseif 0 165 | !n 166 | else 167 | !n 168 | endif 169 | 170 | 171 | if 0 172 | !n 173 | elseif 0 174 | !n 175 | else 176 | !y 177 | endif 178 | endif 179 | 180 | if !count == 4**2 : db 1 : endif 181 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | branches: [ master, asar_19, asar_2_beta ] 6 | pull_request: 7 | branches: [ master, asar_19, asar_2_beta ] 8 | 9 | env: 10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 11 | BUILD_TYPE: MinSizeRel 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | matrix: 17 | include: 18 | - name: win64 19 | os: windows-2022 20 | cmake_opts: '-G "Visual Studio 17 2022"' 21 | - name: win32 22 | os: windows-2022 23 | cmake_opts: '-G "Visual Studio 17 2022" -A Win32' 24 | - name: ubuntu 25 | os: ubuntu-24.04 26 | cmake_opts: '-DASAR_USE_SANITIZER=ON' 27 | - name: osx 28 | os: macos-14 29 | name: ${{ matrix.name }} 30 | runs-on: ${{ matrix.os }} 31 | 32 | steps: 33 | - uses: actions/checkout@v4 34 | with: 35 | fetch-depth: 0 36 | 37 | - name: Configure CMake 38 | run: cmake -S ${{github.workspace}}/src -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ${{ matrix.cmake_opts }} 39 | 40 | - name: Build 41 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 42 | 43 | # Uncomment this to get a debug shell on the actions runner 44 | #- name: debug stuff 45 | # uses: mxschmitt/action-tmate@v3 46 | 47 | - name: Tests 48 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target run-tests 49 | 50 | - uses: actions/upload-artifact@v4 51 | if: ${{ matrix.name == 'win64' || matrix.name == 'win32' }} 52 | with: 53 | # only on windows: 54 | # on osx, the binaries wouldn't be easily runnable anyways due to code 55 | # signing bullshit; on linux, the test binaries are built with asan and 56 | # i don't want to distribute those 57 | name: ${{ matrix.name }}-binaries 58 | path: | 59 | ${{ github.workspace }}/build/asar/bin/**/asar.exe 60 | ${{ github.workspace }}/build/asar/lib/**/asar.dll 61 | -------------------------------------------------------------------------------- /tests/bankcross.asm: -------------------------------------------------------------------------------- 1 | ;`007FFF 2 | ;`00 3 | ;`008000 4 | ;`00 5 | ;`FF FF 00 6 | ;`00 80 01 7 | ;`00 00 00 8 | ;`FF FF 00 9 | ;`00 80 01 10 | ;`EA EA 11 | ;`00FFFF 12 | ;`00 13 | ;`010000 14 | ;`00 15 | ;`FF FF 00 16 | ;`00 00 01 17 | ;`00 00 00 18 | ;`FF FF 00 19 | ;`00 00 01 20 | ;`EA EA 21 | ;`000015 22 | ;`00 00 00 23 | ;`00 00 00 24 | ;`15 00 00 25 | ;`18 00 00 26 | ;`020000 27 | ;`00 00 00 28 | ;`00 00 00 29 | ;`15 00 00 30 | ;`18 00 00 31 | ;`02FFF8 32 | ;`00 01 02 03 33 | ;`057FFC 34 | ;`30 20 10 00 35 | ;`FF FE 36 | ;`037FF8 37 | ;`42 42 42 42 42 42 42 42 38 | 39 | ;disabling mapper change warning as a bonus test instead 40 | ;of requiring the warning like other tests 41 | warnings disable Wmapper_already_set 42 | warnings disable Wfeature_deprecated 43 | check bankcross off 44 | 45 | org $00FFFF 46 | 47 | First: 48 | db $00 49 | 50 | Second: 51 | db $00 52 | 53 | dl First 54 | dl Second 55 | 56 | check bankcross on 57 | 58 | db $00,$00,$00 59 | 60 | dl First 61 | dl Second 62 | 63 | nop #2 64 | 65 | 66 | 67 | norom 68 | 69 | check bankcross off 70 | 71 | org $00FFFF 72 | 73 | Third: 74 | db $00 75 | 76 | Fourth: 77 | db $00 78 | 79 | dl Third 80 | dl Fourth 81 | 82 | check bankcross on 83 | 84 | db $00,$00,$00 85 | 86 | dl Third 87 | dl Fourth 88 | 89 | nop #2 90 | 91 | 92 | 93 | check bankcross off 94 | 95 | org $000015 96 | 97 | Fifth: 98 | dl $000000 99 | Sixth: 100 | dl $000000 101 | dl Fifth 102 | dl Sixth 103 | 104 | check bankcross on 105 | 106 | 107 | 108 | org $020000 109 | 110 | check bankcross off 111 | 112 | base $000015 113 | 114 | Seventh: 115 | dl $000000 116 | 117 | Eigth: 118 | dl $000000 119 | dl Seventh 120 | dl Eigth 121 | 122 | base off 123 | 124 | check bankcross on 125 | 126 | 127 | 128 | lorom 129 | org $05FFF8 130 | db $00 131 | db $01 132 | db $02 133 | db $03 134 | 135 | norom 136 | check bankcross off 137 | 138 | org $057FFC 139 | base $00002 140 | 141 | db $30 142 | db $20 143 | db $10 144 | db $00 ;x7FFF 145 | db $FF ;x8000 146 | db $FE 147 | 148 | lorom 149 | base off 150 | check bankcross on 151 | 152 | org $06FFF8 153 | padbyte $42 : pad $078000 154 | -------------------------------------------------------------------------------- /src/asar/warnings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ASAR_WARNING_RANGE_START 1000 4 | 5 | // NOTE: Don't reorder these. That would change their ID. 6 | // If you need to remove one, stub it out. 7 | // If you need to add one, add it at the end (before warning_id_end). 8 | // Keep in sync with asar_warnings. 9 | enum asar_warning_id : int 10 | { 11 | warning_id_start = ASAR_WARNING_RANGE_START, 12 | 13 | warning_id_relative_path_used, 14 | 15 | warning_id_rom_too_short, 16 | warning_id_rom_title_incorrect, 17 | 18 | warning_id_65816_yy_x_does_not_exist, 19 | warning_id_65816_xx_y_assume_16_bit, 20 | warning_id_spc700_assuming_8_bit, 21 | 22 | warning_id_cross_platform_path, 23 | 24 | warning_id_missing_org, 25 | warning_id_set_middle_byte, 26 | 27 | warning_id_unrecognized_special_command, 28 | 29 | warning_id_freespace_leaked, 30 | 31 | warning_id_warn_command, 32 | 33 | warning_id_implicitly_sized_immediate, 34 | 35 | warning_id_xkas_deprecated, 36 | warning_id_xkas_eat_parentheses, 37 | warning_id_xkas_label_access, 38 | warning_id_xkas_warnpc_relaxed, 39 | warning_id_xkas_style_conditional, 40 | warning_id_xkas_patch, 41 | warning_id_xkas_incsrc_relative, 42 | warning_id_convert_to_asar, 43 | 44 | warning_id_fixed_deprecated, 45 | 46 | warning_id_autoclear_deprecated, 47 | 48 | warning_id_check_memory_file, 49 | 50 | warning_id_if_not_condition_deprecated, 51 | 52 | warning_id_function_redefined, 53 | 54 | warning_id_datasize_last_label, 55 | warning_id_datasize_exceeds_size, 56 | 57 | warning_id_mapper_already_set, 58 | warning_id_feature_deprecated, 59 | 60 | warning_id_byte_order_mark_utf8, 61 | 62 | warning_id_optimization_settings, 63 | 64 | warning_id_end, 65 | warning_id_count = warning_id_end - warning_id_start - 1 66 | }; 67 | 68 | void asar_throw_warning(int whichpass, asar_warning_id warnid, ...); 69 | const char* get_warning_name(asar_warning_id warnid); 70 | 71 | void set_warning_enabled(asar_warning_id warnid, bool enabled); 72 | 73 | // Supported string format: wXXXX, WXXXX or XXXX. 74 | // Returns warning_id_end if the string is malformed 75 | // or the ID wasn't found. 76 | asar_warning_id parse_warning_id_from_string(const char* string, int warn_pass = 0); 77 | 78 | void reset_warnings_to_default(); 79 | 80 | void push_warnings(bool warnings_command = true); 81 | void pull_warnings(bool warnings_command = true); 82 | void verify_warnings(); 83 | -------------------------------------------------------------------------------- /docs/shared/highlight_js_asar/styles/default.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Original highlight.js style (c) Ivan Sagalaev 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | background: #F0F0F0; 12 | } 13 | 14 | 15 | /* Base color: saturation 0; */ 16 | 17 | .hljs, 18 | .hljs-subst { 19 | color: #444; 20 | } 21 | 22 | .hljs-comment { 23 | color: #009900; 24 | } 25 | 26 | .hljs-attribute, 27 | .hljs-selector-tag, 28 | .hljs-meta-keyword, 29 | .hljs-doctag, 30 | .hljs-name { 31 | font-weight: bold; 32 | } 33 | 34 | 35 | /* User color: hue: 0 */ 36 | 37 | .hljs-type, 38 | .hljs-number, 39 | .hljs-selector-id, 40 | .hljs-selector-class, 41 | .hljs-quote, 42 | .hljs-template-tag, 43 | .hljs-deletion { 44 | color: #FF8000; 45 | font-weight: normal; 46 | } 47 | 48 | .hljs-string { 49 | color: #737373; 50 | font-weight: normal; 51 | font-style: normal; 52 | } 53 | 54 | .hljs-title, 55 | .hljs-section { 56 | color: #880000; 57 | font-weight: bold; 58 | } 59 | 60 | .hljs-regexp, 61 | .hljs-variable, 62 | .hljs-template-variable, 63 | .hljs-link, 64 | .hljs-selector-attr, 65 | .hljs-selector-pseudo { 66 | color: #BC6060; 67 | } 68 | 69 | 70 | /* Language color: hue: 90; */ 71 | 72 | .hljs-literal { 73 | color: #78A960; 74 | font-weight: normal; 75 | font-style: normal; 76 | } 77 | 78 | .hljs-bullet, 79 | .hljs-code, 80 | .hljs-addition { 81 | color: #397300; 82 | } 83 | 84 | 85 | .hljs-keyword, 86 | .hljs-opcodes { 87 | color: #0000ff; 88 | font-weight: bold; 89 | font-style: normal; 90 | } 91 | 92 | .hljs-builtin { 93 | color: #800000; 94 | font-weight: bold; 95 | font-style: italic; 96 | } 97 | 98 | .hljs-label, 99 | .hljs-special { 100 | color: #800000; 101 | font-weight: normal; 102 | font-style: normal; 103 | } 104 | 105 | .hljs-function, 106 | .hljs-define { 107 | color: #800000; 108 | font-weight: bold; 109 | font-style: normal; 110 | } 111 | 112 | 113 | /* Meta color: hue: 200 */ 114 | 115 | .hljs-keywords { 116 | color: #8080ff; 117 | font-weight: normal; 118 | font-style: normal; 119 | } 120 | 121 | .hljs-meta-string { 122 | color: #4d99bf; 123 | } 124 | 125 | 126 | /* Misc effects */ 127 | 128 | .hljs-emphasis { 129 | font-style: italic; 130 | } 131 | 132 | .hljs-strong { 133 | font-weight: bold; 134 | } -------------------------------------------------------------------------------- /tests/v150features.asm: -------------------------------------------------------------------------------- 1 | ;`000000 2 | ;`00 00 00 00 80 00 00 00 20 00 00 00 00 00 20 FF FF 3F 00 80 80 00 80 81 00 80 C0 FF FF FF 3 | ;`000100 4 | ;`00 80 00 00 80 01 00 00 00 00 80 00 00 80 00 00 00 00 00 80 00 FF FF 3F 00 00 C0 00 80 C0 00 80 C1 FF FF FF 5 | ;`000200 6 | ;`00 00 40 00 80 40 00 00 60 00 00 00 00 00 20 FF FF 3F 00 80 80 00 80 C0 FF FF FF 00 80 00 00 80 01 00 80 40 7 | ;`000300 8 | ;`00 80 40 00 80 41 00 00 40 00 80 40 00 80 00 00 00 00 00 80 00 FF FF 3F 00 00 C0 00 80 C0 FF FF FF 00 00 40 00 80 40 00 80 41 9 | ;`008000 10 | ;`FF FF FF 11 | ;`00 01 02 03 04 05 06 07 00 01 02 03 12 | ;`warnWmapper_already_set 13 | ;`warnWmapper_already_set 14 | ;`warnWmapper_already_set 15 | ;`warnWmapper_already_set 16 | asar 1.50 17 | 18 | lorom 19 | org $008000 20 | 21 | dl snestopc($008000) 22 | dl snestopc($018000) 23 | dl snestopc($408000) 24 | dl snestopc($808000) 25 | dl snestopc($C08000) 26 | dl snestopc($FFFFFF) 27 | 28 | dl pctosnes($000000) 29 | dl pctosnes($008000) 30 | dl pctosnes($200000) 31 | dl pctosnes($3FFFFF) 32 | 33 | 34 | hirom 35 | org $400100 36 | 37 | dl snestopc($008000) 38 | dl snestopc($018000) 39 | dl snestopc($400000) 40 | dl snestopc($408000) 41 | dl snestopc($808000) 42 | dl snestopc($C00000) 43 | dl snestopc($C08000) 44 | dl snestopc($FFFFFF) 45 | 46 | dl pctosnes($000000) 47 | dl pctosnes($008000) 48 | dl pctosnes($018000) 49 | dl pctosnes($3FFFFF) 50 | 51 | 52 | exlorom 53 | org $808200 54 | 55 | dl snestopc($008000) 56 | dl snestopc($018000) 57 | dl snestopc($408000) 58 | dl snestopc($808000) 59 | dl snestopc($C08000) 60 | dl snestopc($FFFFFF) 61 | 62 | dl pctosnes($000000) 63 | dl pctosnes($200000) 64 | dl pctosnes($3FFFFF) 65 | dl pctosnes($400000) 66 | dl pctosnes($408000) 67 | dl pctosnes($600000) 68 | 69 | 70 | exhirom 71 | org $C00300 72 | 73 | dl snestopc($008000) 74 | dl snestopc($018000) 75 | dl snestopc($400000) 76 | dl snestopc($408000) 77 | dl snestopc($808000) 78 | dl snestopc($C00000) 79 | dl snestopc($C08000) 80 | dl snestopc($FFFFFF) 81 | 82 | dl pctosnes($000000) 83 | dl pctosnes($008000) 84 | dl pctosnes($3FFFFF) 85 | dl pctosnes($400000) 86 | dl pctosnes($408000) 87 | dl pctosnes($418000) 88 | 89 | lorom 90 | org $018000 91 | 92 | dl $FFFFFF 93 | 94 | incsrc "data/pushtable1.asm" 95 | db "ABCD" 96 | 97 | pushtable 98 | 99 | incsrc "data/pushtable2.asm" 100 | db "ABCD" 101 | 102 | pulltable 103 | 104 | db "ABCD" 105 | 106 | -------------------------------------------------------------------------------- /tests/optimizer.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`AD 00 00 AF 00 00 7E 3 | ;`AD 00 00 A5 00 4 | ;`A5 00 5 | ;`AD 00 00 A5 00 6 | ;`AF 00 10 01 AD 00 10 7 | ;`AD 00 10 AD 00 80 AF 00 80 01 8 | ;` 9 | ;`80000 53 54 41 52 26 00 D9 FF 10 | ;` AD 08 80 AF 00 00 00 AF 00 60 02 11 | ;` AD 00 00 AF 00 10 01 AF 00 60 02 12 | ;` AD 00 00 AD 00 10 AD 00 60 AF 00 80 00 13 | ;` AF 37 80 90 14 | ;`53 54 41 52 16 00 E9 FF 15 | ;` AF 08 80 90 AD 37 80 AF 00 00 00 16 | ;` AF 00 00 7E 17 | ;` AF 00 00 7E AF 00 60 02 18 | ;`FFFFF 00 19 | 20 | ;1 line above = 1 block of code below 21 | ;namespace optimize_dp_flag { 22 | ; enum : int { 23 | ; NONE, //don't optimize 24 | ; RAM, //bank 7E only (always uses dp base) 25 | ; ALWAYS //bank 00-3F[|80] and 7E (always uses dp base) 26 | ; }; 27 | ;} 28 | ; 29 | ;extern int optimize_dp; 30 | ;extern int dp_base; 31 | ; 32 | ;namespace optimize_address_flag { 33 | ; enum : int { 34 | ; DEFAULT,//simply use optimizeforbank 35 | ; RAM, //default+bank 7E only RAM address < $2000 36 | ; MIRRORS //ram+if optimizeforbank is 00-3F[|80] and address < $8000 37 | ; }; 38 | ;} 39 | ; 40 | ;extern int optimize_address; 41 | 42 | ;quick ref 43 | ;lda long = AF 44 | ;lda word = AD 45 | ;lda dp = A5 46 | 47 | 48 | 49 | org $008000 50 | 51 | base $000000 52 | struct test_00 53 | .test: skip $100 54 | .test_0100: skip 1 55 | endstruct 56 | 57 | base $011000 58 | struct test_word 59 | .up: skip 1 60 | endstruct 61 | 62 | base $7E0000 63 | struct test_7E 64 | .test: skip $1000 65 | .word: skip 1 66 | 67 | endstruct 68 | 69 | mirror = $026000 70 | nonmirror = $008000 71 | nonmirror01 = $018000 72 | 73 | base off 74 | optimize address default 75 | optimize dp none 76 | ;test default asar optimization (bank only) 77 | lda test_00.test 78 | lda test_7E.test 79 | 80 | ;test optimizations of dp on with dp base as default 0000 in bank 7E only 81 | ;optimize dp ram 82 | optimize dp ram 83 | dpbase $0000 84 | lda test_00.test 85 | lda test_7E.test 86 | 87 | optimize dp always 88 | lda test_00.test 89 | 90 | dpbase $0100 91 | lda test_00.test 92 | lda test_00.test_0100 93 | 94 | optimize dp none 95 | optimize address ram 96 | lda test_word.up 97 | lda test_7E.word 98 | 99 | optimize address mirrors 100 | lda test_word.up 101 | lda nonmirror 102 | lda nonmirror01 103 | 104 | freecode cleaned 105 | optimize dp none 106 | optimize address default 107 | freec: 108 | lda freec 109 | lda test_00.test 110 | lda mirror 111 | 112 | optimize address ram 113 | lda test_7E.test 114 | lda test_word.up 115 | lda mirror 116 | 117 | optimize address mirrors 118 | lda test_7E.test 119 | lda test_word.up 120 | lda mirror 121 | lda nonmirror 122 | 123 | lda freed 124 | 125 | freedata cleaned 126 | freed: 127 | optimize address default 128 | lda freec 129 | lda freed 130 | lda test_00.test 131 | 132 | optimize address ram 133 | lda test_7E.test 134 | 135 | optimize address mirrors 136 | lda test_7E.test 137 | lda mirror 138 | -------------------------------------------------------------------------------- /src/asar/assembleblock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum { arch_65816, arch_spc700, arch_spc700_inline, arch_superfx }; 4 | extern int arch; 5 | 6 | bool assemblemapper(char** word, int numwords); 7 | 8 | struct snes_struct { 9 | string parent; 10 | int base_end; 11 | int struct_size; 12 | int object_size; 13 | bool is_static; 14 | }; 15 | 16 | extern assocarr structs; 17 | 18 | 19 | struct snes_label { 20 | unsigned int pos; 21 | bool is_static; 22 | 23 | snes_label() 24 | { 25 | pos = 0; 26 | is_static = false; 27 | } 28 | }; 29 | 30 | 31 | // RPG Hacker: Really the only purpose of this struct is to support pushtable and pulltable 32 | // Also don't know where else to put this, so putting it in this header 33 | struct chartabledata { 34 | unsigned int table[256]; 35 | }; 36 | 37 | extern chartabledata table; 38 | 39 | struct whiletracker { 40 | bool iswhile; 41 | int startline; 42 | bool cond; 43 | bool is_for; 44 | string for_variable; 45 | string for_var_backup; 46 | bool for_has_var_backup; 47 | int for_start; 48 | int for_end; 49 | int for_cur; 50 | }; 51 | 52 | extern autoarray whilestatus; 53 | 54 | // 0 - not first block, not in for 55 | // 1 - first block 56 | // 2 - inside single-line for 57 | // 3 - after endfor 58 | extern int single_line_for_tracker; 59 | 60 | bool confirmname(const char * name); 61 | string posneglabelname(const char ** input, bool define); 62 | 63 | void write1_pick(unsigned int num); 64 | void write2(unsigned int num); 65 | void write3(unsigned int num); 66 | void write4(unsigned int num); 67 | 68 | int read1(int snespos); 69 | int read2(int snespos); 70 | int read3(int snespos); 71 | 72 | int snestopc_pick(int addr); 73 | 74 | int getlenfromchar(char c); 75 | 76 | snes_label labelval(const char ** rawname, bool define = false); 77 | snes_label labelval(char ** rawname, bool define = false); 78 | snes_label labelval(string name, bool define = false); 79 | bool labelval(const char ** rawname, snes_label * rval, bool define = false); 80 | bool labelval(char ** rawname, snes_label * rval, bool define = false); 81 | bool labelval(string name, snes_label * rval, bool define = false); 82 | 83 | const char * safedequote(char * str); 84 | 85 | void checkbankcross(); 86 | 87 | void initstuff(); 88 | void finishpass(); 89 | 90 | void assembleblock(const char * block, bool isspecialline); 91 | 92 | extern int snespos; 93 | extern int realsnespos; 94 | extern int startpos; 95 | extern int realstartpos; 96 | 97 | extern int bytes; 98 | 99 | extern int numopcodes; 100 | 101 | extern bool warnxkas; 102 | 103 | extern int numif; 104 | extern int numtrue; 105 | 106 | extern bool emulatexkas; 107 | 108 | extern int freespaceextra; 109 | extern bool freespace_is_freecode; 110 | 111 | extern assocarr labels; 112 | 113 | extern autoarray* macroposlabels; 114 | extern autoarray* macroneglabels; 115 | extern autoarray* macrosublabels; 116 | 117 | extern autoarray sublabels; 118 | extern string ns; 119 | extern autoarray namespace_list; 120 | 121 | extern autoarray includeonce; 122 | -------------------------------------------------------------------------------- /src/generate_manual_tables.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import html 4 | 5 | os.chdir(os.path.dirname(__file__)) 6 | 7 | class Warning: 8 | name: str 9 | description: str 10 | enabled: bool 11 | 12 | def __init__(self, name, description, enabled = True): 13 | self.name = name 14 | self.description = description 15 | self.enabled = enabled 16 | 17 | def __str__(self): 18 | return f'W{self.name}{self.description}{self.enabled}\n' 19 | 20 | class Errors: 21 | name: str 22 | description: str 23 | 24 | def __init__(self, name, description): 25 | self.name = name 26 | self.description = description 27 | 28 | def __str__(self): 29 | return f'E{self.name}{self.description}\n' 30 | 31 | 32 | with open('asar/errors.cpp', 'r') as f: 33 | errors_text = f.readlines() 34 | 35 | with open('asar/warnings.cpp', 'r') as f: 36 | warnings_text = f.readlines() 37 | 38 | warnings: list[Warning] = [] 39 | errors: list[Errors] = [] 40 | 41 | warning_lines = [] 42 | error_lines = [] 43 | for line in warnings_text: 44 | if 'WRN(' in line and not line.startswith('#define'): 45 | warning_lines.append(line.strip()) 46 | for line in errors_text: 47 | if 'ERR(' in line and not line.startswith('#define'): 48 | error_lines.append(line.strip()) 49 | 50 | pre_text = """ 51 | 52 | 53 | 54 | 55 | Asar User Manual - #TITLE# 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | """ 65 | pre_error_text = """ 66 | 67 | 68 | 69 | 70 | """ 71 | pre_warning_text = """ 72 | 73 | 74 | 75 | 76 | 77 | """ 78 | post_text = """ 79 |
Error nameError message
Warning nameWarning messageEnabled by default
80 | 81 | 82 | """ 83 | 84 | warning_pattern = re.compile(r'WRN\((.*?)\),\s*"(.*)"\s*,?\s*(true|false)?\s*}') 85 | error_pattern = re.compile(r'ERR\((.*?)\),\s*"(.*)"\s*}') 86 | for warning in warning_lines: 87 | name, description, enabled = re.findall(warning_pattern, warning)[0] 88 | description = html.escape(description.replace(r'\"', '"')) 89 | warnings.append(Warning(name, description, enabled != 'false')) 90 | 91 | for error in error_lines: 92 | name, description = re.findall(error_pattern, error)[0] 93 | description = html.escape(description.replace(r'\"', '"')) 94 | errors.append(Errors(name, description)) 95 | 96 | with open('../docs/manual/errors-list.html', 'w') as f: 97 | f.write(pre_text.replace('#TITLE#', "Error list")) 98 | f.write(pre_error_text) 99 | for error in errors: 100 | f.write(str(error)) 101 | f.write(post_text) 102 | 103 | with open('../docs/manual/warnings-list.html', 'w') as f: 104 | f.write(pre_text.replace('#TITLE#', "Warning list")) 105 | f.write(pre_warning_text) 106 | for warning in warnings: 107 | f.write(str(warning)) 108 | f.write(post_text) 109 | -------------------------------------------------------------------------------- /src/asar/asar.h: -------------------------------------------------------------------------------- 1 | #if (defined(__sun__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)) && !defined(linux) 2 | #error Please use -Dlinux on non-Linux Unix-likes. 3 | #endif 4 | 5 | #if defined(linux) && !defined(stricmp) 6 | #error Please use -Dstricmp=strcasecmp on Unix-like systems. 7 | #endif 8 | 9 | #pragma once 10 | #define Asar 11 | 12 | #include "autoarray.h" 13 | #include "assocarr.h" 14 | #include "libstr.h" 15 | #include "libsmw.h" 16 | #include "errors.h" 17 | #include "virtualfile.h" 18 | #include 19 | 20 | extern unsigned const char * romdata_r; 21 | extern int romlen_r; 22 | 23 | #define clean(string) do { string.qreplace(", ", ",", true); string.qreplace(" ", " ", true); \ 24 | strip_whitespace(string); string.qreplace("\t", " ", true);} while(0) 25 | #define clean_and_trim(string) do { clean(string); string.qreplace(" ", "", true);} while(0) 26 | 27 | int getlen(const char * str, bool optimizebankextraction=false); 28 | bool is_hex_constant(const char * str); 29 | 30 | bool validatedefinename(const char * name); 31 | 32 | string create_symbols_file(string format, uint32_t romCrc); 33 | 34 | void parse_std_includes(const char* textfile, autoarray& outarray); 35 | void parse_std_defines(const char* textfile); 36 | 37 | void reseteverything(); 38 | 39 | void resolvedefines(string& out, const char * start); 40 | 41 | int get_version_int(); 42 | 43 | bool setmapper(); 44 | 45 | void assemblefile(const char * filename, bool toplevel); 46 | void assembleline(const char * fname, int linenum, const char * line); 47 | 48 | bool file_included_once(const char* file); 49 | 50 | string getdecor(); 51 | 52 | asar_error_id vfile_error_to_error_id(virtual_file_error vfile_error); 53 | 54 | virtual_file_error asar_get_last_io_error(); 55 | 56 | extern volatile int recursioncount; 57 | extern int pass; 58 | 59 | class recurseblock { 60 | public: 61 | recurseblock() 62 | { 63 | recursioncount++; 64 | if (recursioncount > 250) asar_throw_error(pass, error_type_fatal, error_id_recursion_limit); 65 | } 66 | ~recurseblock() 67 | { 68 | recursioncount--; 69 | } 70 | }; 71 | 72 | extern const int asarver_maj; 73 | extern const int asarver_min; 74 | extern const int asarver_bug; 75 | extern const bool asarver_beta; 76 | extern bool default_math_pri; 77 | extern bool default_math_round_off; 78 | 79 | extern bool asarverallowed; 80 | extern bool istoplevel; 81 | 82 | extern bool moreonline; 83 | extern bool moreonlinecond; 84 | extern int fakeendif; 85 | 86 | extern bool checksum_fix_enabled; 87 | extern bool force_checksum_fix; 88 | 89 | extern string callerfilename; 90 | extern int callerline; 91 | extern string thisfilename; 92 | extern int thisline; 93 | extern const char * thisblock; 94 | 95 | extern int incsrcdepth; 96 | 97 | extern bool ignoretitleerrors; 98 | 99 | extern int repeatnext; 100 | 101 | extern int optimizeforbank; 102 | 103 | //this is a trick to namespace an enum to avoid name collision without too much verbosity 104 | //could technically name the enum too but this is fine for now. 105 | namespace optimize_dp_flag { 106 | enum : int { 107 | NONE, //don't optimize 108 | RAM, //bank 7E only (always uses dp base) 109 | ALWAYS //bank 00-3F[|80] and 7E (always uses dp base) 110 | }; 111 | } 112 | 113 | extern int optimize_dp; 114 | extern int dp_base; 115 | extern bool set_optimize_dp; 116 | extern bool set_optimize_address; 117 | 118 | namespace optimize_address_flag { 119 | enum : int { 120 | DEFAULT,//simply use optimizeforbank 121 | RAM, //default+bank 7E only RAM address < $2000 122 | MIRRORS //ram+if optimizeforbank is 00-3F[|80] and address < $8000 123 | }; 124 | } 125 | 126 | extern int optimize_address; 127 | 128 | extern bool errored; 129 | 130 | extern assocarr clidefines; 131 | 132 | extern virtual_filesystem* filesystem; 133 | 134 | extern assocarr defines; 135 | 136 | extern assocarr builtindefines; 137 | -------------------------------------------------------------------------------- /src/asar/autoarray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "std-includes.h" 4 | 5 | //Note: T must be a pointer type, or stuff will screw up. To make a pointer last longer than this object, assign nullptr to it and it won't free the old one. 6 | template class autoptr { 7 | T ptr; 8 | public: 9 | operator T() const 10 | { 11 | return ptr; 12 | } 13 | 14 | autoptr& operator=(T ptr_) 15 | { 16 | ptr = ptr_; 17 | return *this; 18 | } 19 | 20 | autoptr() 21 | { 22 | ptr = nullptr; 23 | } 24 | 25 | autoptr(T ptr_) 26 | { 27 | ptr = ptr_; 28 | } 29 | 30 | autoptr(const autoptr& ptr_) 31 | { 32 | ptr = ptr_.ptr; 33 | } 34 | 35 | ~autoptr() 36 | { 37 | if (ptr) free((void*)ptr); 38 | } 39 | }; 40 | 41 | template class autoarray { 42 | public: 43 | int count; 44 | 45 | private: 46 | T* ptr; 47 | int bufferlen; 48 | 49 | T dummy; 50 | static const int default_size = 128; 51 | 52 | const T& getconst(int id) const 53 | { 54 | if (id < 0) return dummy; 55 | if (id >= count) return dummy; 56 | return ptr[id]; 57 | } 58 | 59 | T& get(int id) 60 | { 61 | if (id < 0) return dummy; 62 | if (id >= bufferlen - 4) 63 | { 64 | resize(id); 65 | } 66 | if (id >= count) 67 | { 68 | for (int i = count;i <= id;i++) new(ptr + i) T(); 69 | count = id + 1; 70 | } 71 | return ptr[id]; 72 | } 73 | 74 | void resize(int size) 75 | { 76 | int oldlen = count; 77 | while (bufferlen <= size + 4) bufferlen *= 2; 78 | T *old = ptr; 79 | ptr = (T*)malloc(sizeof(T)*(size_t)bufferlen); 80 | for(int i = 0; i < oldlen; i++){ 81 | new(ptr + i) T(); 82 | ptr[i] = static_cast(old[i]); 83 | } 84 | free(old); 85 | memset(ptr + oldlen, 0, (size_t)(bufferlen - oldlen) * sizeof(T)); 86 | } 87 | 88 | public: 89 | 90 | void reset(int keep = 0) 91 | { 92 | if (keep >= count) return; 93 | for (int i = keep;i < count;i++) ptr[i].~T(); 94 | memset(ptr + keep, 0, (size_t)(count - keep) * sizeof(T)); 95 | if (keep < bufferlen / 2) 96 | { 97 | while (keep < bufferlen / 2 && bufferlen>8) bufferlen /= 2; 98 | T *old = ptr; 99 | ptr = (T*)malloc(sizeof(T)*(size_t)bufferlen); 100 | for(int i = 0; i < keep; i++){ 101 | new(ptr + i) T(); 102 | ptr[i] = static_cast(old[i]); 103 | } 104 | free(old); 105 | 106 | } 107 | count = keep; 108 | } 109 | 110 | T& operator[](int id) 111 | { 112 | return get(id); 113 | } 114 | 115 | const T& operator[](int id) const 116 | { 117 | return getconst(id); 118 | } 119 | 120 | operator T*() 121 | { 122 | return ptr; 123 | } 124 | 125 | operator const T*() const 126 | { 127 | return ptr; 128 | } 129 | 130 | T& append(const T& item) 131 | { 132 | return (get(count) = item); 133 | } 134 | 135 | //insert is not safe for non pod types!!! 136 | void insert(int pos) 137 | { 138 | if (pos<0 || pos>count) return; 139 | if (count >= bufferlen - 4) 140 | { 141 | resize(count); 142 | } 143 | memmove(ptr + pos + 1, ptr + pos, sizeof(T)*(count - pos)); 144 | memset(ptr + pos, 0, sizeof(T)); 145 | new(ptr + pos) T(); 146 | count++; 147 | } 148 | 149 | void insert(int pos, const T& item) 150 | { 151 | if (pos<0 || pos>count) return; 152 | if (count >= bufferlen - 4) 153 | { 154 | resize(count); 155 | } 156 | memmove(ptr + pos + 1, ptr + pos, sizeof(T)*(size_t)(count - pos)); 157 | memset(ptr + pos, 0, sizeof(T)); 158 | new(ptr + pos) T(); 159 | ptr[pos] = item; 160 | count++; 161 | } 162 | 163 | void remove(int id) 164 | { 165 | if (id < 0 || id >= count) return; 166 | count--; 167 | ptr[id].~T(); 168 | for(int i = id; i < count; i++){ 169 | ptr[i] = static_cast(ptr[i+1]); 170 | } 171 | } 172 | 173 | autoarray() 174 | { 175 | ptr = (T*)malloc(sizeof(T) * default_size); 176 | memset(ptr, 0, default_size*sizeof(T)); 177 | bufferlen = default_size; 178 | count = 0; 179 | } 180 | 181 | ~autoarray() 182 | { 183 | for (int i = 0;i < count;i++) ptr[i].~T(); 184 | free(ptr); 185 | } 186 | 187 | #ifdef SERIALIZER 188 | void serialize(serializer& s) 189 | { 190 | if (s.serializing) s(count); 191 | else 192 | { 193 | int i; 194 | s(i); 195 | get(i - 1); 196 | } 197 | for (int i = 0;i < count;i++) s(ptr[i]); 198 | } 199 | #endif 200 | #define SERIALIZER_BANNED 201 | }; 202 | -------------------------------------------------------------------------------- /src/asar/libcon.cpp: -------------------------------------------------------------------------------- 1 | #include "std-includes.h" 2 | #include "libcon.h" 3 | #include 4 | 5 | static char * progname; 6 | static char ** args; 7 | static int argsleft; 8 | bool libcon_interactive; 9 | static const char * usage; 10 | 11 | static volatile bool confirmclose=true; 12 | void libcon_pause() 13 | { 14 | if (confirmclose) 15 | { 16 | confirmclose=false; 17 | #if defined(_WIN32) 18 | system("pause"); 19 | #else 20 | printf("Press Enter to continue"); 21 | getchar(); 22 | #endif 23 | confirmclose=true; 24 | } 25 | } 26 | 27 | void libcon_badusage() 28 | { 29 | printf("usage: %s %s", progname, usage); 30 | exit(1); 31 | } 32 | 33 | static const char * getarg(bool tellusage, const char * defval= nullptr) 34 | { 35 | if (!argsleft) 36 | { 37 | if (tellusage) libcon_badusage(); 38 | return defval; 39 | } 40 | args++; 41 | argsleft--; 42 | return args[0]; 43 | } 44 | 45 | static const char * getfname(bool tellusage, const char * defval= nullptr) 46 | { 47 | return getarg(tellusage, defval); 48 | //char * rval=malloc(char, 256); 49 | //char * rvalend=rval; 50 | //*rval=0; 51 | //while (!strchr(rval, '.')) 52 | //{ 53 | // char * thisword=getarg(false, nullptr); 54 | // if (!thisword) 55 | // { 56 | // if (tellusage) libcon_badusage(); 57 | // else return defval; 58 | // } 59 | // if (rval!=rvalend) *(rvalend++)=' '; 60 | // rvalend+=sprintf(rvalend, "%s", thisword); 61 | //} 62 | //return rval; 63 | } 64 | 65 | static const char * requirestrfromuser(const char * question, bool filename) 66 | { 67 | confirmclose=false; 68 | char * rval=(char*)malloc(256); 69 | *rval=0; 70 | while (!strchr(rval, '\n') || *rval=='\n') 71 | { 72 | *rval=0; 73 | printf("%s ", question); 74 | (void)fgets(rval, 250, stdin); 75 | } 76 | *strchr(rval, '\n')=0; 77 | confirmclose=true; 78 | #ifdef _WIN32 79 | if (filename && rval[0]=='"' && rval[2]==':') 80 | { 81 | char * rvalend=strchr(rval, '\0'); 82 | if (rvalend[-1]=='"') rvalend[-1]='\0'; 83 | return rval+1; 84 | } 85 | #endif 86 | return rval; 87 | } 88 | 89 | static const char * requeststrfromuser(const char * question, bool filename, const char * defval) 90 | { 91 | confirmclose=false; 92 | char * rval=(char*)malloc(256); 93 | *rval=0; 94 | printf("%s ", question); 95 | (void)fgets(rval, 250, stdin); 96 | *strchr(rval, '\n')=0; 97 | confirmclose=true; 98 | if (!*rval) return defval; 99 | #ifdef _WIN32 100 | if (filename && rval[0]=='"' && rval[2]==':') 101 | { 102 | char * rvalend=strchr(rval, '\0'); 103 | if (rvalend[-1]=='"') rvalend[-1]='\0'; 104 | return rval+1; 105 | } 106 | #endif 107 | return rval; 108 | } 109 | 110 | void libcon_init(int argc, char ** argv, const char * usage_) 111 | { 112 | progname=argv[0]; 113 | args=argv; 114 | argsleft=argc-1; 115 | usage=usage_; 116 | libcon_interactive=(!argsleft); 117 | #if defined(_WIN32) 118 | if (libcon_interactive) atexit(libcon_pause); 119 | #endif 120 | } 121 | 122 | const char * libcon_require(const char * desc) 123 | { 124 | if (libcon_interactive) return requirestrfromuser(desc, false); 125 | else return getarg(true); 126 | } 127 | 128 | const char * libcon_require_filename(const char * desc) 129 | { 130 | if (libcon_interactive) return requirestrfromuser(desc, true); 131 | else return getfname(true); 132 | } 133 | 134 | const char * libcon_optional(const char * desc, const char * defval) 135 | { 136 | if (libcon_interactive) return requeststrfromuser(desc, false, defval); 137 | else return getarg(false, defval); 138 | } 139 | 140 | const char * libcon_optional_filename(const char * desc, const char * defval) 141 | { 142 | if (libcon_interactive) return requeststrfromuser(desc, true, defval); 143 | else return getfname(false, defval); 144 | } 145 | 146 | const char * libcon_option() 147 | { 148 | if (!libcon_interactive && argsleft && args[1][0]=='-') return getarg(false); 149 | return nullptr; 150 | } 151 | 152 | const char * libcon_option_value() 153 | { 154 | if (!libcon_interactive) return getarg(false); 155 | return nullptr; 156 | } 157 | 158 | const char * libcon_question(const char * desc, const char * defval) 159 | { 160 | if (libcon_interactive) return libcon_optional(desc, defval); 161 | return defval; 162 | } 163 | 164 | bool libcon_question_bool(const char * desc, bool defval) 165 | { 166 | if (!libcon_interactive) return defval; 167 | while (true) 168 | { 169 | const char * answer=requeststrfromuser(desc, false, defval?"y":"n"); 170 | if (!stricmp(answer, "y") || !stricmp(answer, "yes")) return true; 171 | if (!stricmp(answer, "n") || !stricmp(answer, "no")) return false; 172 | } 173 | } 174 | 175 | void libcon_end() 176 | { 177 | if (!libcon_interactive && argsleft) libcon_badusage(); 178 | } 179 | -------------------------------------------------------------------------------- /src/asar-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9.0) 2 | 3 | OPTION(ASAR_GEN_EXE_TEST "Build Asar standalone application test suite" ON) 4 | OPTION(ASAR_GEN_DLL_TEST "Build Asar shared library test suite" ON) 5 | 6 | # Shared settings for Asar test applications 7 | 8 | macro(set_asar_test_shared_properties target) 9 | # Maximum warning level 10 | if(MSVC) 11 | target_compile_definitions(${target} PRIVATE "_CRT_SECURE_NO_WARNINGS") 12 | target_compile_options(${target} PRIVATE /Wall /MT /EHa) 13 | 14 | # These certainly aren't worth a warning, though 15 | target_compile_options(${target} PRIVATE 16 | /wd4514 # unreferenced inline function removed 17 | /wd4710 # function not inlined 18 | /wd4711 # function selected for automatic inline expansion 19 | /wd4820 # 'bytes' bytes padding added after construct 'member_name' 20 | /wd4464 # relativ include path contains '..' 21 | ) 22 | 23 | if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^LLVM-.*$") 24 | target_compile_options(${target} PRIVATE 25 | -Wno-old-style-cast # use of old-style-cast 26 | -Wno-unknown-argument # unknown argument ignored in clang-cl 27 | -Wno-unused-command-line-argument # argument unused during compilation 28 | -Wno-c++98-compat # 'x' is incompatible with C++98 29 | -Wno-c++98-compat-pedantic 30 | -Wno-missing-noreturn # 'x' could be declared with attribute 'noreturn' 31 | -Wno-float-equal # comparting floating point with == or != is unsafe 32 | -Wno-covered-switch-default # default label in switch which covers all enumeration values 33 | -Wno-varargs # passing an object that undergoes default argument promotion to 'va_start' has undefined behavior 34 | 35 | # RPG Hacker: These two are really nasty, but not easily fixable in Asar, so have to disable them... 36 | -Wno-exit-time-destructors # declaration requires an exit-time destructor 37 | -Wno-global-constructors # delcaration requires a global destructor 38 | ) 39 | endif() 40 | 41 | if(MSVC_VERSION VERSION_LESS "1900") 42 | target_compile_features(${target} PRIVATE cxx_std_11) 43 | else() 44 | # MSVC throws errors in STL headers when building with MSVC 2017 without C++14... 45 | target_compile_features(${target} PRIVATE cxx_std_14) 46 | endif() 47 | else() 48 | if(NOT MINGW) 49 | # Not available nor needed on mingw 50 | target_link_libraries(${target} dl) 51 | endif() 52 | target_compile_options(${target} PRIVATE -Wall -pedantic 53 | -Wno-varargs # passing an object that undergoes default argument promotion to 'va_start' has undefined behavior 54 | -Wno-unused-result # ignoring return value 55 | ) 56 | 57 | # Static link for MinGW 58 | if(MINGW) 59 | target_compile_options(${target} PRIVATE -static -static-libgcc -s) 60 | target_link_libraries(${target} PRIVATE -static -static-libgcc -s) 61 | endif() 62 | 63 | # for some reason this isn't available on MSVC? 64 | target_compile_features(${target} PRIVATE c_std_99) 65 | target_compile_features(${target} PRIVATE cxx_std_11) 66 | endif() 67 | endmacro() 68 | 69 | set(CXX_EXTENSIONS OFF) 70 | 71 | add_custom_target(run-tests) 72 | set_property(TARGET run-tests PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 73 | 74 | if(ASAR_GEN_EXE_TEST) 75 | add_executable( 76 | asar-app-test 77 | 78 | "${CMAKE_CURRENT_SOURCE_DIR}/test.cpp" 79 | ) 80 | 81 | set_asar_test_shared_properties(asar-app-test) 82 | 83 | add_custom_target(run-app-test 84 | asar-app-test "$" "${CMAKE_CURRENT_SOURCE_DIR}/../../tests" "${CMAKE_CURRENT_SOURCE_DIR}/../../dummy_rom.sfc" "${CMAKE_CURRENT_BINARY_DIR}/tests-tmp-app" 85 | VERBATIM) 86 | add_dependencies(run-tests run-app-test) 87 | set_property(TARGET run-app-test PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 88 | endif() 89 | 90 | if(ASAR_GEN_DLL_TEST) 91 | add_executable( 92 | asar-dll-test 93 | 94 | "${CMAKE_CURRENT_SOURCE_DIR}/test.cpp" 95 | 96 | "${CMAKE_CURRENT_SOURCE_DIR}/../asar-dll-bindings/c/asardll.c" 97 | "${CMAKE_CURRENT_SOURCE_DIR}/../asar-dll-bindings/c/asardll.h" 98 | ) 99 | 100 | target_include_directories(asar-dll-test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../asar-dll-bindings/c/") 101 | target_compile_definitions(asar-dll-test PRIVATE ASAR_TEST_DLL) 102 | 103 | set_asar_test_shared_properties(asar-dll-test) 104 | 105 | if(ASAR_USE_SANITIZER) 106 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address") 107 | set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address") 108 | endif() 109 | 110 | add_custom_target(run-dll-test 111 | asar-dll-test "$" "${CMAKE_CURRENT_SOURCE_DIR}/../../tests" "${CMAKE_CURRENT_SOURCE_DIR}/../../dummy_rom.sfc" "${CMAKE_CURRENT_BINARY_DIR}/tests-tmp-dll" 112 | VERBATIM) 113 | add_dependencies(run-tests run-dll-test) 114 | set_property(TARGET run-dll-test PROPERTY EXCLUDE_FROM_DEFAULT_BUILD TRUE) 115 | endif() 116 | -------------------------------------------------------------------------------- /src/asar-dll-bindings/c/asardll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if defined(_WIN32) 6 | # if defined(_MSC_VER) 7 | # pragma warning(push) 8 | # pragma warning(disable : 4255) 9 | # pragma warning(disable : 4668) 10 | # endif 11 | 12 | # include 13 | # include 14 | 15 | # if defined(_MSC_VER) 16 | # pragma warning(pop) 17 | # endif 18 | 19 | inline static void * getlib(void) 20 | { 21 | void * ret_val = LoadLibraryW(L"asar.dll"); 22 | 23 | if (ret_val == NULL) 24 | { 25 | // TODO: Add a better method of error checking? This won't do much for people who are using 26 | // Asar with a GUI application, they probably won't see this error output. 27 | char buf[1024]; 28 | sprintf(buf, "Failed to load Asar DLL! HRESULT: 0x%08x\n", (unsigned int)HRESULT_FROM_WIN32(GetLastError())); 29 | printf("%s", buf); 30 | OutputDebugStringA(buf); 31 | } 32 | 33 | return ret_val; 34 | } 35 | 36 | inline static void * getlibfrompath(const char * path) 37 | { 38 | int required_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); 39 | if (required_size <= 0) return NULL; 40 | 41 | wchar_t* path_buf = (wchar_t*)malloc((size_t)required_size * sizeof(wchar_t)); 42 | if (path_buf == NULL) return NULL; 43 | 44 | int converted_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, path_buf, required_size); 45 | 46 | if (converted_size == 0) 47 | { 48 | return NULL; 49 | } 50 | 51 | void * ret_val = LoadLibraryW(path_buf); 52 | free(path_buf); 53 | 54 | if (ret_val == NULL) 55 | { 56 | // TODO: Add a better method of error checking? This won't do much for people who are using 57 | // Asar with a GUI application, they probably won't see this error output. 58 | char buf[1024]; 59 | sprintf(buf, "Failed to load Asar DLL! HRESULT: 0x%08x\n", (unsigned int)HRESULT_FROM_WIN32(GetLastError())); 60 | printf("%s", buf); 61 | OutputDebugStringA(buf); 62 | } 63 | 64 | return ret_val; 65 | } 66 | 67 | inline static bool setfunction(void* target, FARPROC fn) 68 | { 69 | memcpy(target, &fn, sizeof(fn)); 70 | return fn; 71 | } 72 | # define loadraw(name, target) require(setfunction(&target, GetProcAddress((HINSTANCE)asardll, name))) 73 | # define closelib(var) FreeLibrary((HINSTANCE)var) 74 | #else 75 | # include 76 | # include 77 | 78 | # ifdef __APPLE__ 79 | # define EXTENSION ".dylib" 80 | # else 81 | # define EXTENSION ".so" 82 | # endif 83 | 84 | inline static void * getlib(void) 85 | { 86 | const char * names[]={"./libasar"EXTENSION, "libasar", NULL}; 87 | for (int i=0;names[i];i++) 88 | { 89 | void * rval=dlopen(names[i], RTLD_LAZY); 90 | const char*e=dlerror(); 91 | if(e)puts(e); 92 | if (rval) return rval; 93 | } 94 | return NULL; 95 | } 96 | 97 | inline static void * getlibfrompath(const char * path) 98 | { 99 | void * rval = dlopen(path, RTLD_LAZY); 100 | const char*e = dlerror(); 101 | if (e)puts(e); 102 | if (rval) return rval; 103 | return NULL; 104 | } 105 | 106 | # define loadraw(name, target) *(void **)(&target)=dlsym(asardll, name); require(target) 107 | # define closelib(var) dlclose(var) 108 | #endif 109 | 110 | #include "asardll.h" 111 | 112 | #undef asarfunc 113 | #undef ASAR_DLL_H_INCLUDED 114 | 115 | #define asarfunc 116 | #include "asardll.h" 117 | 118 | static void * asardll=NULL; 119 | 120 | static bool (*asar_i_init)(void); 121 | static void(*asar_i_close)(void); 122 | 123 | #define require(b) if (!(b)) { asardll=NULL; return false; } 124 | #define loadi(name) loadraw("asar_"#name, asar_i_##name) 125 | #define load(name) loadraw("asar_"#name, asar_##name) 126 | 127 | static bool asar_init_shared(void) 128 | { 129 | loadi(init); 130 | loadi(close); 131 | load(version); 132 | load(apiversion); 133 | load(reset); 134 | load(patch); 135 | load(patch_ex); 136 | load(maxromsize); 137 | load(geterrors); 138 | load(getwarnings); 139 | load(getprints); 140 | load(getalllabels); 141 | load(getlabelval); 142 | load(getdefine); 143 | load(getalldefines); 144 | load(resolvedefines); 145 | load(math); 146 | load(getwrittenblocks); 147 | load(getmapper); 148 | load(getsymbolsfile); 149 | if (asar_apiversion() < expectedapiversion || (asar_apiversion() / 100) > (expectedapiversion / 100)) return false; 150 | require(asar_i_init()); 151 | return true; 152 | } 153 | 154 | bool asar_init(void) 155 | { 156 | if (asardll) return true; 157 | asardll=getlib(); 158 | require(asardll); 159 | if (!asar_init_shared()) return false; 160 | return true; 161 | } 162 | 163 | bool asar_init_with_dll_path(const char * dllpath) 164 | { 165 | if (asardll) return true; 166 | asardll = getlibfrompath(dllpath); 167 | require(asardll); 168 | if (!asar_init_shared()) return false; 169 | return true; 170 | } 171 | 172 | void asar_close(void) 173 | { 174 | if (!asardll) return; 175 | asar_i_close(); 176 | closelib(asardll); 177 | asardll=NULL; 178 | } 179 | -------------------------------------------------------------------------------- /docs/manual/warnings-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Asar User Manual - Warning list 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
Warning nameWarning messageEnabled by default
Wrelative_path_usedRelative %s path passed to asar_patch_ex() - please use absolute paths only to prevent undefined behavior!True
Wrom_too_shortROM is too short to have a title. (Expected '%s')True
Wrom_title_incorrectROM title is incorrect. Expected '%s', got '%s'.True
W65816_yy_x_does_not_exist($yy),x does not exist, assuming $yy,x.True
W65816_xx_y_assume_16_bit%s $xx,y is not valid with 8-bit parameters, assuming 16-bit.True
Wspc700_assuming_8_bitThis opcode does not exist with 16-bit parameters, assuming 8-bit.True
Wcross_platform_pathThis patch may not assemble cleanly on all platforms. Please use / instead.True
Wmissing_orgMissing org or freespace command.True
Wset_middle_byteIt would be wise to set the 008000 bit of this address.True
Wunrecognized_special_commandUnrecognized special command - your version of Asar might be outdated.True
Wfreespace_leakedThis freespace appears to be leaked.True
Wwarn_commandwarn command%sTrue
Wimplicitly_sized_immediateImplicitly sized immediate.False
Wxkas_deprecatedxkas support is being deprecated and will be removed in a future version of Asar. Please use an older version of Asar (<=1.50) if you need it.True
Wxkas_eat_parenthesesxkas compatibility warning: Unlike xkas, Asar does not eat parentheses after defines.True
Wxkas_label_accessxkas compatibility warning: Label access is always 24bit in emulation mode, but may be 16bit in native mode.True
Wxkas_warnpc_relaxedxkas conversion warning : warnpc is relaxed one byte in Asar.True
Wxkas_style_conditionalxkas-style conditional compilation detected. Please use the if command instead.True
Wxkas_patchIf you want to assemble an xkas patch, add ;@xkas at the top or you may run into a couple of problems.True
Wxkas_incsrc_relativexkas compatibility warning: incsrc and incbin look for files relative to the patch in Asar, but xkas looks relative to the assembler.True
Wconvert_to_asarConvert the patch to native Asar format instead of making an Asar-only xkas patch.True
Wfixed_deprecatedthe 'fixed' parameter on freespace/freecode/freedata is deprecated - please use 'static' instead.True
Wautoclear_deprecated'autoclear' is deprecated - please use 'autoclean' instead.True
Wcheck_memory_fileAccessing file '%s' which is not in memory while W%d is enabled.False
Wif_not_condition_deprecated'if !condition' is deprecated - please use 'if not(condition)' instead.True
Wfunction_redefinedFunction '%s' redefined.True
Wdatasize_last_labelDatasize used on last detected label '%s'.True
Wdatasize_exceeds_sizeDatasize exceeds 0xFFFF for label '%s'.True
Wmapper_already_setA mapper has already been selected.True
Wfeature_deprecatedDEPRECATION NOTIFICATION: Feature "%s" is deprecated and will be REMOVED in the future. Please update your code to conform to newer styles. Suggested work around: %s.True
Wbyte_order_mark_utf8UTF-8 byte order mark detected and skipped.True
Woptimization_settingsIn Asar 2.0, the default optimization settings will change to `optimize dp always` and `optimize address mirrors`, which changes this instruction's argument from %d to %d bytes. Either specify the desired settings manually or use explicit length suffixes to silence this warning.True
55 | 56 | 57 | -------------------------------------------------------------------------------- /ext/sublime-text/65c816.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | # A rather bad syntax file for Sublime Text. But hey, atleast it supports goto definition with defines! 4 | # I can't seem to get commenting to work correctly though 5 | # also aaaa sublime text syntax files are hard 6 | name: Asar 65c816 assembly 7 | file_extensions: 8 | - asm 9 | scope: source.asar 10 | 11 | contexts: 12 | # The prototype context is prepended to all contexts but those setting 13 | # meta_include_prototype: false. 14 | prototype: 15 | - include: comments 16 | 17 | main: 18 | # The main context is the initial starting point of our syntax. 19 | # Include other contexts from here (or specify them directly). 20 | - include: operators 21 | - include: mnemonics 22 | - include: macroDeclStart 23 | - include: keywords 24 | - include: builtinFuncs 25 | - include: defineDeclStart 26 | - include: numbers 27 | - include: macros 28 | - include: defines 29 | - include: strings 30 | 31 | keywords: 32 | - match: '\b(?i:lorom|hirom|exlorom|exhirom|sa1rom|fullsa1rom|sfxrom|norom|macro|endmacro|incbin|incsrc|fillbyte|fillword|filllong|filldword|fill|pad|padbyte|padword|padlong|paddword|table|cleartable|skip|namespace|import|print|org|warnpc|base|on|off|freespaceuse|hex|freespace|freecode|freedata|ram|noram|align|cleaned|static|autoclean|autoclear|prot|pushpc|pullpc|function|if|else|elseif|endif|while|endwhile|for|endfor|assert|arch|65816|spc700|spc700-inline|superfx|math|pri|round|warn|xkas|bank|noassume|auto|asar|include|includefrom|error|warn|skip|double|round|pushtable|pulltable|db|dw|dl|dd|global)\b' 33 | scope: keyword.control.asar 34 | 35 | operators: 36 | - match: '(\+|\-|\*|/)' 37 | scope: keyword.operator.arithmetic.asar 38 | - match: '(=|?=|+=|:=|#=)' 39 | scope: keyword.operator.assignment.asar 40 | - match: '(<<|>>|\||&|~|\^)' 41 | scope: keyword.operator.bitwise.asar 42 | - match: '(==|!=|>=|<=|>|<|&&|\|\|)' 43 | scope: keyword.operator.logical.asar 44 | - match: '(\(|\)|,|:|->|#|\[|\]|\\)' 45 | scope: keyword.operator.asar 46 | 47 | mnemonics: 48 | - match: '\b(?i:adc|and|asl|bcc|blt|bcs|bge|beq|bit|bmi|bne|bpl|bra|brk|brl|bvc|bvs|clc|cld|cli|clv|cmp|cop|cpx|cpy|dec|dea|dex|dey|eor|inc|ina|inx|iny|jmp|jml|jsr|jsl|lda|ldx|ldy|lsr|mvn|mvp|nop|ora|pea|pei|per|pha|phb|phd|phk|php|phx|phy|pla|plb|pld|plp|plx|ply|rep|rol|ror|rti|rtl|rts|sbc|sec|sed|sei|sep|sta|stp|stx|sty|stz|tax|tay|tcd|tcs|tdc|trb|tsc|tsb|tsx|txa|txs|txy|tya|tyx|wai|wdm|xba|xce)(\.(?i:b|w|l))?\b' 49 | scope: keyword.other.mnemonic.asar 50 | - match: '\b(?i:x|y|s)\b' 51 | scope: keyword.other.register.asar 52 | 53 | builtinFuncs: 54 | - match: '\b(read1|read2|read3|read4|canread1|canread2|canread4|sqrt|sin|cos|tan|asin|acos|atan|arcsin|arccos|arctan|log|log10|log2|_read1|_read2|_read3|_read4|_canread1|_canread2|_canread4|_sqrt|_sin|_cos|_tan|_asin|_acos|_atan|_arcsin|_arccos|_arctan|_log|_log10|_log2|readfile1|_readfile1|readfile2|_readfile2|readfile3|_readfile3|readfile4|_readfile4|canreadfile1|_canreadfile1|canreadfile2|_canreadfile2|canreadfile3|_canreadfile3|canreadfile4|_canreadfile4|canreadfile|_canreadfile|snestopc|_snestopc|pctosnes|_pctosnes|max|_max|min|_min|clamp|_clamp|safediv|_safediv|select|_select|not|_not|equal|_equal|notequal|_notequal|less|_less|lessequal|_lessequal|greater|_greater|greaterequal|_greaterequal|and|_and|or|_or|nand|_nand|nor|_nor|xor|_xor)\b' 55 | scope: variable.function.asar 56 | 57 | defines: 58 | - match: '![a-zA-Z_0-9]*' 59 | scope: variable.other.asar 60 | 61 | macros: 62 | - match: '%[a-zA-Z_0-9]*' 63 | scope: variable.function.asar 64 | 65 | defineDeclStart: 66 | - match: '^\s*!' 67 | push: define_name 68 | 69 | define_name: 70 | - meta_include_prototype: false 71 | - meta_scope: variable.other.asar 72 | - match: '[a-zA-Z0-9_]*' 73 | scope: entity.name.type.asar 74 | pop: true 75 | 76 | macroDeclStart: 77 | - match: '^\s*macro %?' 78 | scope: keyword.operator.asar 79 | push: macro_name 80 | 81 | numbers: 82 | - match: '\b[0-9]+\b' 83 | scope: constant.numeric.integer.asar 84 | - match: '\$[0-9a-fA-F]+\b' 85 | scope: constant.numeric.hex.asar 86 | - match: '%[01]+\b' 87 | scope: constant.numeric.bin.asar 88 | 89 | macro_name: 90 | - meta_content_scope: variable.function.asar 91 | - match: '%' 92 | scope: keyword.control.asar 93 | - match: '[a-zA-Z0-9_]*' 94 | scope: entity.name.type.asar 95 | - match: '\(' 96 | scope: keyword.operator.asar 97 | pop: true 98 | 99 | strings: 100 | - match: '"' 101 | scope: punctuation.definition.string.begin.asar 102 | push: inside_string 103 | 104 | inside_string: 105 | - meta_include_prototype: false 106 | - meta_scope: string.quoted.double.asar 107 | #- match: '\.' 108 | # scope: constant.character.escape.asar 109 | - match: '"' 110 | scope: punctuation.definition.string.end.asar 111 | pop: true 112 | 113 | comments: 114 | - match: ';' 115 | scope: punctuation.definition.comment.asar 116 | push: 117 | # This is an anonymous context push for brevity. 118 | - meta_scope: comment.line.double-slash.asar 119 | - match: $\n? 120 | pop: true 121 | -------------------------------------------------------------------------------- /tests/120freespaces.asm: -------------------------------------------------------------------------------- 1 | ;`+ 2 | ;`07FD7 0A 3 | ;`FFFFF 00 4 | ;`80000 5 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 6 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 7 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 8 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 9 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 10 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 11 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 12 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 13 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 14 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 15 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 16 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 17 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 18 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 19 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 20 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 21 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 22 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 23 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 24 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 25 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 26 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 27 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 28 | ;`53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 53 54 41 52 00 00 FF FF EA 29 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 30 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 31 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 32 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 33 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 34 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 35 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 36 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 37 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 38 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 39 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 40 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 41 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 42 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 43 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 44 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 45 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 46 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 47 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 48 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 49 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 50 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 51 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 52 | freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP : freecode cleaned : NOP 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asar 2 | [![build status (GitHub Actions)](https://github.com/RPGHacker/asar/actions/workflows/cmake.yml/badge.svg)](https://github.com/RPGHacker/asar/actions/workflows/cmake.yml) [![muncher build status (r9.pm)](https://r9.pm/asar-badge.php?branch=asar_19)](https://r9.pm/asar-overview.php) 3 | 4 | Asar is an SNES assembler designed for applying patches to existing ROM images, or creating new ROM images from scratch. It supports 65c816, SPC700, and Super FX architectures. It was originally created by Alcaro, modelled after [xkas v0.06](https://www.romhacking.net/utilities/269/) by byuu. 5 | 6 | For a guide on using Asar (including how to write patches), see [`README.txt`](https://github.com/RPGHacker/asar/blob/master/README.txt). A version of the user manual can also be found [online](https://rpghacker.github.io/asar/manual/). This readme was made with tool programmers and contributors in mind. 7 | 8 | ## Building 9 | You can build Asar with [CMake](https://cmake.org). On Linux, the most basic build would look like `cmake src && make`. On Windows, using Visual Studio, you would do `cmake src`, then open the project file it generates in Visual Studio and click Build. Alternately, you might be able to use Visual Studio's [CMake integration](https://docs.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio). 10 | 11 | If you'd rather not build from source, check out the [Releases](https://github.com/RPGHacker/asar/releases) page. 12 | 13 | ## Asar DLL 14 | Asar can also be built as a DLL. This makes it easier and faster to use in other programs (such as a sprite insertion tool). You can find documentation on the DLL API in the respective bindings (asardll.h, asar.cs, asar.py). 15 | 16 | ## Asar as a static library 17 | Asar can also be built as a static library. All "out-facing" functions are in interface-lib.h. This is useful for embedding Asar in other programs which don't want to use DLLs. The easiest way to add asar as a static library to your project is to add it as a git submodule 18 | 19 | `git submodule add https://github.com/RPGHacker/asar ` 20 | 21 | then add the following to your CMakeLists.txt: 22 | ```CMake 23 | add_subdirectory(/src) 24 | get_target_property(ASAR_INCLUDE_DIR asar-static INCLUDE_DIRECTORIES) 25 | include_directories(${ASAR_INCLUDE_DIR}) 26 | target_link_libraries(YourTarget PUBLIC asar-static) 27 | ``` 28 | to be able to include the header files. It is also recommended to turn off every build in target in asar except the static one using the appropriate CMake options. You will need to make sure that your project has an Asar compatible license. 29 | 30 | ## Folder layout 31 | * `docs` contains the source of the manual and changelog. 32 | (You can view an online version of the manual [here](https://rpghacker.github.io/asar/manual/) and an online version of the changelog [here](https://rpghacker.github.io/asar/changelog/)). 33 | * `ext` contains syntax highlighting files for Notepad++ and Sublime Text 34 | * `src` 35 | * `asar` contains the source code of the main app and DLL 36 | * `asar-tests` contains code for the testing application (both the app test and DLL test) 37 | * `asar-dll-bindings` contains bindings of the Asar DLL to other languages (currently C/C++, C# and Python) 38 | * `tests` contains tests to verify Asar works correctly 39 | 40 | ## Test format 41 | *Please note that these tests are intended for use with Asar's test suite. Only contributors will need to use this functionality - people who just want to create and apply patches don't need to worry about it.* 42 | 43 | At the beginning of your ASM files, you can write tests to ensure the correct values were written to the ROM after patching is complete. (It's common to use a SMW ROM, but there's also a dummy ROM included that should work with all tests.) 44 | 45 | These two characters should precede each test line, so that Asar sees them as comments and ignores them. 46 | ``` 47 | ;` 48 | ``` 49 | 50 | * 5-6 hex digits - the ROM offset to check 51 | * Specify it as a PC address, not a SNES address 52 | * When left blank, it defaults to `0x000000` 53 | * 2 hex digits - a byte for it to check for 54 | * You can specify more than one, like in the examples below, and it will automatically increment the offset. 55 | * A line starting with `+` tells the testing app to patch the SMW ROM instead of creating a new ROM 56 | * `#` followed by a decimal number tells the testing app to apply the patch that number of times repeatedly 57 | * `errE{name}` and `warnW{name}` (where `{name}` is the name of an error or warning) means that the test is expected to throw that specific error or warning while patching. The test will succeed only if the number and order of errors and warnings thrown exactly matches what's specified here. Be wary that Asar uses multiple passes and throws errors and warnings across multiple of them. This can make the actual order in which errors and warnings are thrown a bit unintuitive. 58 | 59 | In addition to the format mentioned above, it's also possible to check for user prints a patch is expected to output (by `print`, `error`, `warn` or `assert` commands). This is done by starting the line with one of the following sequences: 60 | ``` 61 | ;E> 62 | ;W> 63 | ;P> 64 | ``` 65 | Where E is for errors/asserts, W is for warnings and P is for prints. Following this sequence, every character up to the end of the current line is a part of the expected string to be output. Note that the test suite also verifies the order of prints within the respective type. So if your patch is expected to output two user-defined errors, they need to be specified exactly in the order in which they are expected to be output. 66 | 67 | **Example tests:** 68 | 69 | This line tests that the bytes `5A`, `40` and `00` (in that order) were written to the start of the ROM. 70 | ``` 71 | ;`5A 40 00 72 | ``` 73 | 74 | This line tests that `22`, `20`, `80` and `90` were written to the ROM offset `0x007606`. 75 | ``` 76 | ;`007606 22 20 80 90 77 | ``` 78 | 79 | This line tests that assembling the patch throws error `Eunknown_command` twice and warning `Wfeature_deprecated` once. 80 | ``` 81 | ;`errEunknown_command 82 | ;`errEunknown_command 83 | ;`warnWfeature_deprecated 84 | ``` 85 | 86 | This line tests that the byte `FF` was written to the start of the ROM, that the string `This is a print.` was printed and that the string `This is a user error.` was output via the error command (which itself also causes error `Eerror_command` to be thrown once). 87 | ``` 88 | ;`FF 89 | ;P>This is a print. 90 | ;E>This is a user error. 91 | ;`errEerror_command 92 | ``` 93 | -------------------------------------------------------------------------------- /src/asar/libsmw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "errors.h" 4 | #include "autoarray.h" 5 | #include 6 | 7 | extern const unsigned char * romdata; 8 | extern int romlen; 9 | extern unsigned char default_freespacebyte; 10 | extern asar_error_id openromerror; 11 | bool openrom(const char * filename, bool confirm=true); 12 | uint32_t closerom(bool save = true); 13 | 14 | enum mapper_t { 15 | invalid_mapper, 16 | lorom, 17 | hirom, 18 | sa1rom, 19 | bigsa1rom, 20 | sfxrom, 21 | exlorom, 22 | exhirom, 23 | norom 24 | } extern mapper; 25 | 26 | extern int sa1banks[8];//only 0, 1, 4, 5 are used 27 | 28 | void writeromdata(int pcoffset, const void * indata, int numbytes); 29 | void writeromdata_byte(int pcoffset, unsigned char indata); 30 | void writeromdata_bytes(int pcoffset, unsigned char indata, int numbytes, bool add_write = true); 31 | 32 | struct writtenblockdata { 33 | int pcoffset; 34 | int snesoffset; 35 | int numbytes; 36 | }; 37 | 38 | extern autoarray writtenblocks; 39 | 40 | inline int snestopc(int addr) 41 | { 42 | if (addr<0 || addr>0xFFFFFF) return -1;//not 24bit 43 | if (mapper==lorom) 44 | { 45 | // randomdude999: The low pages ($0000-$7FFF) of banks 70-7D are used 46 | // for SRAM, the high pages are available for ROM data though 47 | if ((addr&0xFE0000)==0x7E0000 ||//wram 48 | (addr&0x408000)==0x000000 ||//hardware regs, ram mirrors, other strange junk 49 | (addr&0x708000)==0x700000)//sram (low parts of banks 70-7D) 50 | return -1; 51 | addr=((addr&0x7F0000)>>1|(addr&0x7FFF)); 52 | return addr; 53 | } 54 | if (mapper==hirom) 55 | { 56 | if ((addr&0xFE0000)==0x7E0000 ||//wram 57 | (addr&0x408000)==0x000000)//hardware regs, ram mirrors, other strange junk 58 | return -1; 59 | return addr&0x3FFFFF; 60 | } 61 | if (mapper==exlorom) 62 | { 63 | if ((addr&0xF00000)==0x700000 ||//wram, sram 64 | (addr&0x408000)==0x000000)//area that shouldn't be used in lorom 65 | return -1; 66 | if (addr&0x800000) 67 | { 68 | addr=((addr&0x7F0000)>>1|(addr&0x7FFF)); 69 | } 70 | else 71 | { 72 | addr=((addr&0x7F0000)>>1|(addr&0x7FFF))+0x400000; 73 | } 74 | return addr; 75 | } 76 | if (mapper==exhirom) 77 | { 78 | if ((addr&0xFE0000)==0x7E0000 ||//wram 79 | (addr&0x408000)==0x000000)//hardware regs, ram mirrors, other strange junk 80 | return -1; 81 | if ((addr&0x800000)==0x000000) return (addr&0x3FFFFF)|0x400000; 82 | return addr&0x3FFFFF; 83 | } 84 | if (mapper==sfxrom) 85 | { 86 | // Asar emulates GSU1, because apparently emulators don't support the extra ROM data from GSU2 87 | if ((addr&0x600000)==0x600000 ||//wram, sram, open bus 88 | (addr&0x408000)==0x000000 ||//hardware regs, ram mirrors, rom mirrors, other strange junk 89 | (addr&0x800000)==0x800000)//fastrom isn't valid either in superfx 90 | return -1; 91 | if (addr&0x400000) return addr&0x3FFFFF; 92 | else return (addr&0x7F0000)>>1|(addr&0x7FFF); 93 | } 94 | if (mapper==sa1rom) 95 | { 96 | if ((addr&0x408000)==0x008000) 97 | { 98 | return sa1banks[(addr&0xE00000)>>21]|((addr&0x1F0000)>>1)|(addr&0x007FFF); 99 | } 100 | if ((addr&0xC00000)==0xC00000) 101 | { 102 | return sa1banks[((addr&0x100000)>>20)|((addr&0x200000)>>19)]|(addr&0x0FFFFF); 103 | } 104 | return -1; 105 | } 106 | if (mapper==bigsa1rom) 107 | { 108 | if ((addr&0xC00000)==0xC00000)//hirom 109 | { 110 | return (addr&0x3FFFFF)|0x400000; 111 | } 112 | if ((addr&0xC00000)==0x000000 || (addr&0xC00000)==0x800000)//lorom 113 | { 114 | if ((addr&0x008000)==0x000000) return -1; 115 | return (addr&0x800000)>>2 | (addr&0x3F0000)>>1 | (addr&0x7FFF); 116 | } 117 | return -1; 118 | } 119 | if (mapper==norom) 120 | { 121 | return addr; 122 | } 123 | return -1; 124 | } 125 | 126 | inline int pctosnes(int addr) 127 | { 128 | if (addr<0) return -1; 129 | if (mapper==lorom) 130 | { 131 | if (addr>=0x400000) return -1; 132 | addr=((addr<<1)&0x7F0000)|(addr&0x7FFF)|0x8000; 133 | return addr|0x800000; 134 | } 135 | if (mapper==hirom) 136 | { 137 | if (addr>=0x400000) return -1; 138 | return addr|0xC00000; 139 | } 140 | if (mapper == exlorom) 141 | { 142 | if (addr>=0x800000) return -1; 143 | if (addr&0x400000) 144 | { 145 | addr-=0x400000; 146 | addr=((addr<<1)&0x7F0000)|(addr&0x7FFF)|0x8000; 147 | return addr; 148 | } 149 | else 150 | { 151 | addr=((addr<<1)&0x7F0000)|(addr&0x7FFF)|0x8000; 152 | return addr|0x800000; 153 | } 154 | } 155 | if (mapper == exhirom) 156 | { 157 | if (addr>=0x800000) return -1; 158 | if (addr&0x400000) return addr; 159 | return addr|0xC00000; 160 | } 161 | if (mapper==sa1rom) 162 | { 163 | for (int i=0;i<8;i++) 164 | { 165 | if (sa1banks[i]==(addr&0x700000)){ return 0x008000|(i<<21)|((addr&0x0F8000)<<1)|(addr&0x7FFF);} 166 | } 167 | return -1; 168 | } 169 | if (mapper==bigsa1rom) 170 | { 171 | if (addr>=0x800000) return -1; 172 | if ((addr&0x400000)==0x400000) 173 | { 174 | return addr|0xC00000; 175 | } 176 | if ((addr&0x600000)==0x000000) 177 | { 178 | return ((addr<<1)&0x3F0000)|0x8000|(addr&0x7FFF); 179 | } 180 | if ((addr&0x600000)==0x200000) 181 | { 182 | return 0x800000|((addr<<1)&0x3F0000)|0x8000|(addr&0x7FFF); 183 | } 184 | return -1; 185 | } 186 | if (mapper==sfxrom) 187 | { 188 | if (addr>=0x200000) return -1; 189 | return ((addr<<1)&0x7F0000)|(addr&0x7FFF)|0x8000; 190 | } 191 | if (mapper==norom) 192 | { 193 | return addr; 194 | } 195 | return -1; 196 | } 197 | 198 | int getpcfreespace(int size, bool isforcode, bool autoexpand=true, bool respectbankborders=true, bool align=false, unsigned char freespacebyte=0x00); 199 | int getsnesfreespace(int size, bool isforcode, bool autoexpand=true, bool respectbankborders=true, bool align=false, unsigned char freespacebyte=0x00); 200 | 201 | void resizerats(int snesaddr, int newlen); 202 | void removerats(int snesaddr, unsigned char clean_byte); 203 | int ratsstart(int pcaddr); 204 | 205 | bool goodchecksum(); 206 | void fixchecksum(); 207 | 208 | void WalkRatsTags(void(*func)(int loc, int len));//This one calls func() for each RATS tag in the ROM. The pointer is SNES format. 209 | void WalkMetadata(int loc, void(*func)(int loc, char * name, int len, const unsigned char * contents));//This one calls func() for each metadata block in the RATS tag whose contents (metadata) start at loc in the ROM. Do not replace name with an invalid metadata name, and note that name is not null terminated. 210 | -------------------------------------------------------------------------------- /tests/arch-65816.asm: -------------------------------------------------------------------------------- 1 | ;`00 00 00 00 01 00 02 00 02 00 03 00 04 00 05 00 06 00 07 00 08 09 00 09 00 00 0A 0B 0C 00 00 0D 00 00 0E 00 00 0F 00 00 00 2 | ;`10 21 11 00 12 00 13 00 14 00 15 00 16 00 17 00 18 19 00 00 1A 1B 1C 00 00 1D 00 00 1E 00 00 1F 00 00 00 3 | ;`20 00 00 21 00 22 00 00 00 23 00 24 00 25 00 26 00 27 00 28 29 00 29 00 00 2A 2B 2C 00 00 2D 00 00 2E 00 00 2F 00 00 00 4 | ;`30 21 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 39 00 00 3A 3B 3C 00 00 3D 00 00 3E 00 00 3F 00 00 00 5 | ;`40 41 00 42 00 42 00 43 00 44 00 00 45 00 46 00 47 00 48 49 00 49 00 00 4A 4B 4C 00 00 4D 00 00 4E 00 00 4F 00 00 00 6 | ;`50 23 51 00 52 00 53 00 54 00 00 55 00 56 00 57 00 58 59 00 00 5A 5B 5C 00 00 00 5D 00 00 5E 00 00 5F 00 00 00 7 | ;`60 61 00 62 00 00 63 00 64 00 65 00 66 00 67 00 68 69 00 69 00 00 6A 6B 6C 00 00 6D 00 00 6E 00 00 6F 00 00 00 8 | ;`70 21 71 00 72 00 73 00 74 00 75 00 76 00 77 00 78 79 00 00 7A 7B 7C 00 00 7D 00 00 7E 00 00 7F 00 00 00 9 | ;`80 24 81 00 82 1F 00 83 00 84 00 85 00 86 00 87 00 88 89 00 89 00 00 8A 8B 8C 00 00 8D 00 00 8E 00 00 8F 00 00 00 10 | ;`90 21 91 00 92 00 93 00 94 00 95 00 96 00 97 00 98 99 00 00 9A 9B 9C 00 00 9D 00 00 9E 00 00 9F 00 00 00 11 | ;`A0 00 A0 00 00 A1 00 A2 00 A2 00 00 A3 00 A4 00 A5 00 A6 00 A7 00 A8 A9 00 A9 00 00 AA AB AC 00 00 AD 00 00 AE 00 00 AF 00 00 00 12 | ;`B0 21 B1 00 B2 00 B3 00 B4 00 B5 00 B6 00 B7 00 B8 B9 00 00 BA BB BC 00 00 BD 00 00 BE 00 00 BF 00 00 00 13 | ;`C0 00 C0 00 00 C1 00 C2 00 C3 00 C4 00 C5 00 C6 00 C7 00 C8 C9 00 C9 00 00 CA CB CC 00 00 CD 00 00 CE 00 00 CF 00 00 00 14 | ;`D0 21 D1 00 D2 00 D3 00 D4 00 D5 00 D6 00 D7 00 D8 D9 00 00 DA DB DC 00 00 DD 00 00 DE 00 00 DF 00 00 00 15 | ;`E0 00 E0 00 00 E1 00 E2 00 E3 00 E4 00 E5 00 E6 00 E7 00 E8 E9 00 E9 00 00 EA EB EC 00 00 ED 00 00 EE 00 00 EF 00 00 00 16 | ;`F0 22 F1 00 F2 00 F3 00 F4 00 00 F5 00 F6 00 F7 00 F8 F9 00 00 FA FB FC 00 00 FD 00 00 FE 00 00 FF 00 00 00 17 | org $008000 18 | 19 | ;00 20 | BRK 21 | BRK #$00 22 | ORA ($00,x) 23 | COP 24 | COP #$00 25 | ORA $00,s 26 | TSB $00 27 | ORA $00 28 | ASL $00 29 | ORA [$00] 30 | PHP 31 | ORA #$00 32 | ORA #$0000 33 | ASL A 34 | PHD 35 | TSB $0000 36 | ORA $0000 37 | ASL $0000 38 | ORA $000000 39 | + 40 | 41 | ;10 42 | BPL + 43 | ORA ($00),y 44 | ORA ($00) 45 | ORA ($00,s),y 46 | TRB $00 47 | ORA $00,x 48 | ASL $00,x 49 | ORA [$00],y 50 | CLC 51 | ORA $0000,y 52 | INC A 53 | TCS 54 | TRB $0000 55 | ORA $0000,x 56 | ASL $0000,x 57 | ORA $000000,x 58 | + 59 | 60 | ;20 61 | JSR $0000 62 | AND ($00,x) 63 | JSL $000000 64 | AND $00,s 65 | BIT $00 66 | AND $00 67 | ROL $00 68 | AND [$00] 69 | PLP 70 | AND #$00 71 | AND #$0000 72 | ROL A 73 | PLD 74 | BIT $0000 75 | AND $0000 76 | ROL $0000 77 | AND $000000 78 | + 79 | 80 | ;30 81 | BMI + 82 | AND ($00),y 83 | AND ($00) 84 | AND ($00,s),y 85 | BIT $00,x 86 | AND $00,x 87 | ROL $00,x 88 | AND [$00],y 89 | SEC 90 | AND $0000,y 91 | DEC A 92 | TSC 93 | BIT $0000,x 94 | AND $0000,x 95 | ROL $0000,x 96 | AND $000000,x 97 | + 98 | 99 | ;40 100 | RTI 101 | EOR ($00,x) 102 | WDM 103 | WDM #$00 104 | EOR $00,s 105 | MVP $00,$00 106 | EOR $00 107 | LSR $00 108 | EOR [$00] 109 | PHA 110 | EOR #$00 111 | EOR #$0000 112 | LSR A 113 | PHK 114 | JMP $0000 115 | EOR $0000 116 | LSR $0000 117 | EOR $000000 118 | + 119 | 120 | ;50 121 | BVC + 122 | EOR ($00),y 123 | EOR ($00) 124 | EOR ($00,s),y 125 | MVN $00,$00 126 | EOR $00,x 127 | LSR $00,x 128 | EOR [$00],y 129 | CLI 130 | EOR $0000,y 131 | PHY 132 | TCD 133 | JML $000000 134 | EOR $0000,x 135 | LSR $0000,x 136 | EOR $000000,x 137 | + 138 | 139 | ;60 140 | RTS 141 | ADC ($00,x) 142 | PER $0000 143 | ADC $00,s 144 | STZ $00 145 | ADC $00 146 | ROR $00 147 | ADC [$00] 148 | PLA 149 | ADC #$00 150 | ADC #$0000 151 | ROR A 152 | RTL 153 | JMP ($0000) 154 | ADC $0000 155 | ROR $0000 156 | ADC $000000 157 | + 158 | 159 | ;70 160 | BVS + 161 | ADC ($00),y 162 | ADC ($00) 163 | ADC ($00,s),y 164 | STZ $00,x 165 | ADC $00,x 166 | ROR $00,x 167 | ADC [$00],y 168 | SEI 169 | ADC $0000,y 170 | PLY 171 | TDC 172 | JMP ($0000,x) 173 | ADC $0000,x 174 | ROR $0000,x 175 | ADC $000000,x 176 | + 177 | 178 | ;80 179 | BRA + 180 | STA ($00,x) 181 | BRL + 182 | STA $00,s 183 | STY $00 184 | STA $00 185 | STX $00 186 | STA [$00] 187 | DEY 188 | BIT #$00 189 | BIT #$0000 190 | TXA 191 | PHB 192 | STY $0000 193 | STA $0000 194 | STX $0000 195 | STA $000000 196 | + 197 | 198 | ;90 199 | BCC + 200 | STA ($00),y 201 | STA ($00) 202 | STA ($00,s),y 203 | STY $00,x 204 | STA $00,x 205 | STX $00,y 206 | STA [$00],y 207 | TYA 208 | STA $0000,y 209 | TXS 210 | TXY 211 | STZ $0000 212 | STA $0000,x 213 | STZ $0000,x 214 | STA $000000,x 215 | + 216 | 217 | ;A0 218 | LDY #$00 219 | LDY #$0000 220 | LDA ($00,x) 221 | LDX #$00 222 | LDX #$0000 223 | LDA $00,s 224 | LDY $00 225 | LDA $00 226 | LDX $00 227 | LDA [$00] 228 | TAY 229 | LDA #$00 230 | LDA #$0000 231 | TAX 232 | PLB 233 | LDY $0000 234 | LDA $0000 235 | LDX $0000 236 | LDA $000000 237 | + 238 | 239 | ;B0 240 | BCS + 241 | LDA ($00),y 242 | LDA ($00) 243 | LDA ($00,s),y 244 | LDY $00,x 245 | LDA $00,x 246 | LDX $00,y 247 | LDA [$00],y 248 | CLV 249 | LDA $0000,y 250 | TSX 251 | TYX 252 | LDY $0000,x 253 | LDA $0000,x 254 | LDX $0000,y 255 | LDA $000000,x 256 | + 257 | 258 | ;C0 259 | CPY #$00 260 | CPY #$0000 261 | CMP ($00,x) 262 | REP #$00 263 | CMP $00,s 264 | CPY $00 265 | CMP $00 266 | DEC $00 267 | CMP [$00] 268 | INY 269 | CMP #$00 270 | CMP #$0000 271 | DEX 272 | WAI 273 | CPY $0000 274 | CMP $0000 275 | DEC $0000 276 | CMP $000000 277 | + 278 | 279 | ;D0 280 | BNE + 281 | CMP ($00),y 282 | CMP ($00) 283 | CMP ($00,s),y 284 | PEI ($00) 285 | CMP $00,x 286 | DEC $00,x 287 | CMP [$00],y 288 | CLD 289 | CMP $0000,y 290 | PHX 291 | STP 292 | JML [$0000] 293 | CMP $0000,x 294 | DEC $0000,x 295 | CMP $000000,x 296 | + 297 | 298 | ;E0 299 | CPX #$00 300 | CPX #$0000 301 | SBC ($00,x) 302 | SEP #$00 303 | SBC $00,s 304 | CPX $00 305 | SBC $00 306 | INC $00 307 | SBC [$00] 308 | INX 309 | SBC #$00 310 | SBC #$0000 311 | NOP 312 | XBA 313 | CPX $0000 314 | SBC $0000 315 | INC $0000 316 | SBC $000000 317 | + 318 | 319 | ;F0 320 | BEQ + 321 | SBC ($00),y 322 | SBC ($00) 323 | SBC ($00,s),y 324 | PEA $0000 325 | SBC $00,x 326 | INC $00,x 327 | SBC [$00],y 328 | SED 329 | SBC $0000,y 330 | PLX 331 | XCE 332 | JSR ($0000,x) 333 | SBC $0000,x 334 | INC $0000,x 335 | SBC $000000,x 336 | + 337 | -------------------------------------------------------------------------------- /tests/opcodesize.asm: -------------------------------------------------------------------------------- 1 | ;`65 00 6D 00 00 6F 00 00 00 75 00 7D 00 00 7F 00 00 00 69 00 69 00 00 2 | ;`25 00 2D 00 00 2F 00 00 00 35 00 3D 00 00 3F 00 00 00 29 00 29 00 00 3 | ;`06 00 0E 00 00 16 00 1E 00 00 4 | ;`24 00 2C 00 00 34 00 3C 00 00 89 00 89 00 00 5 | ;`C5 00 CD 00 00 CF 00 00 00 D5 00 DD 00 00 DF 00 00 00 C9 00 C9 00 00 6 | ;`E4 00 EC 00 00 E0 00 E0 00 00 7 | ;`C4 00 CC 00 00 C0 00 C0 00 00 8 | ;`C6 00 CE 00 00 D6 00 DE 00 00 9 | ;`45 00 4D 00 00 4F 00 00 00 55 00 5D 00 00 5F 00 00 00 49 00 49 00 00 10 | ;`E6 00 EE 00 00 F6 00 FE 00 00 11 | ;`A5 00 AD 00 00 AF 00 00 00 B5 00 BD 00 00 BF 00 00 00 A9 00 A9 00 00 12 | ;`A6 00 AE 00 00 B6 00 BE 00 00 A2 00 A2 00 00 13 | ;`A4 00 AC 00 00 B4 00 BC 00 00 A0 00 A0 00 00 14 | ;`46 00 4E 00 00 56 00 5E 00 00 15 | ;`05 00 0D 00 00 0F 00 00 00 15 00 1D 00 00 1F 00 00 00 09 00 09 00 00 16 | ;`26 00 2E 00 00 36 00 3E 00 00 17 | ;`66 00 6E 00 00 76 00 7E 00 00 18 | ;`E5 00 ED 00 00 EF 00 00 00 F5 00 FD 00 00 FF 00 00 00 E9 00 E9 00 00 19 | ;`85 00 8D 00 00 8F 00 00 00 95 00 9D 00 00 9F 00 00 00 20 | ;`86 00 8E 00 00 21 | ;`84 00 8C 00 00 22 | ;`64 00 9C 00 00 74 00 9E 00 00 23 | ;`14 00 1C 00 00 24 | ;`04 00 0C 00 00 25 | ;`84 00 85 00 00 94 00 95 00 00 26 | ;`24 00 25 00 00 34 00 35 00 00 27 | ;`0B 00 0C 00 00 28 | ;`64 00 65 00 00 74 00 75 00 00 29 | ;`3E 00 1E 00 00 30 | ;`7E 00 5E 00 00 31 | ;`8B 00 8C 00 00 32 | ;`44 00 45 00 00 54 00 55 00 00 33 | ;`AB 00 AC 00 00 34 | ;`4B 00 4C 00 00 35 | ;`E4 00 E5 00 00 F4 00 F5 00 00 36 | ;`F8 00 E9 00 00 37 | ;`EB 00 EC 00 00 38 | ;`C4 00 C5 00 00 D4 00 D5 00 00 39 | ;`D8 00 C9 00 00 40 | ;`CB 00 CC 00 00 41 | ;`04 00 05 00 00 14 00 15 00 00 42 | ;`2B 00 2C 00 00 43 | ;`6B 00 6C 00 00 44 | ;`A4 00 A5 00 00 B4 00 B5 00 00 45 | ;`84 00 85 00 00 94 00 95 00 00 46 | ;`24 00 25 00 00 34 00 35 00 00 47 | ;`0B 00 0C 00 00 48 | ;`64 00 65 00 00 74 00 75 00 00 49 | ;`3E 00 1E 00 00 50 | ;`7E 00 5E 00 00 51 | ;`8B 00 8C 00 00 52 | ;`44 00 45 00 00 54 00 55 00 00 53 | ;`AB 00 AC 00 00 54 | ;`4B 00 4C 00 00 55 | ;`E4 00 E5 00 00 F4 00 F5 00 00 56 | ;`F8 00 E9 00 00 57 | ;`EB 00 EC 00 00 58 | ;`C4 00 C5 00 00 D4 00 D5 00 00 59 | ;`D8 00 C9 00 00 60 | ;`CB 00 CC 00 00 61 | ;`04 00 05 00 00 14 00 15 00 00 62 | ;`2B 00 2C 00 00 63 | ;`6B 00 6C 00 00 64 | ;`A4 00 A5 00 00 B4 00 B5 00 00 65 | 66 | arch 65816 67 | org $008000 68 | 69 | adc.b $00 70 | adc.w $00 71 | adc.l $00 72 | adc.b $00,X 73 | adc.w $00,X 74 | adc.l $00,X 75 | adc.b #$00 76 | adc.w #$00 77 | 78 | and.b $00 79 | and.w $00 80 | and.l $00 81 | and.b $00,X 82 | and.w $00,X 83 | and.l $00,X 84 | and.b #$00 85 | and.w #$00 86 | 87 | asl.b $00 88 | asl.w $00 89 | asl.b $00,X 90 | asl.w $00,X 91 | 92 | bit.b $00 93 | bit.w $00 94 | bit.b $00,X 95 | bit.w $00,X 96 | bit.b #$00 97 | bit.w #$00 98 | 99 | cmp.b $00 100 | cmp.w $00 101 | cmp.l $00 102 | cmp.b $00,X 103 | cmp.w $00,X 104 | cmp.l $00,X 105 | cmp.b #$00 106 | cmp.w #$00 107 | 108 | cpx.b $00 109 | cpx.w $00 110 | cpx.b #$00 111 | cpx.w #$00 112 | 113 | cpy.b $00 114 | cpy.w $00 115 | cpy.b #$00 116 | cpy.w #$00 117 | 118 | dec.b $00 119 | dec.w $00 120 | dec.b $00,X 121 | dec.w $00,X 122 | 123 | eor.b $00 124 | eor.w $00 125 | eor.l $00 126 | eor.b $00,X 127 | eor.w $00,X 128 | eor.l $00,X 129 | eor.b #$00 130 | eor.w #$00 131 | 132 | inc.b $00 133 | inc.w $00 134 | inc.b $00,X 135 | inc.w $00,X 136 | 137 | lda.b $00 138 | lda.w $00 139 | lda.l $00 140 | lda.b $00,X 141 | lda.w $00,X 142 | lda.l $00,X 143 | lda.b #$00 144 | lda.w #$00 145 | 146 | ldx.b $00 147 | ldx.w $00 148 | ldx.b $00,Y 149 | ldx.w $00,Y 150 | ldx.b #$00 151 | ldx.w #$00 152 | 153 | ldy.b $00 154 | ldy.w $00 155 | ldy.b $00,X 156 | ldy.w $00,X 157 | ldy.b #$00 158 | ldy.w #$00 159 | 160 | lsr.b $00 161 | lsr.w $00 162 | lsr.b $00,X 163 | lsr.w $00,X 164 | 165 | ora.b $00 166 | ora.w $00 167 | ora.l $00 168 | ora.b $00,X 169 | ora.w $00,X 170 | ora.l $00,X 171 | ora.b #$00 172 | ora.w #$00 173 | 174 | rol.b $00 175 | rol.w $00 176 | rol.b $00,X 177 | rol.w $00,X 178 | 179 | ror.b $00 180 | ror.w $00 181 | ror.b $00,X 182 | ror.w $00,X 183 | 184 | sbc.b $00 185 | sbc.w $00 186 | sbc.l $00 187 | sbc.b $00,X 188 | sbc.w $00,X 189 | sbc.l $00,X 190 | sbc.b #$00 191 | sbc.w #$00 192 | 193 | sta.b $00 194 | sta.w $00 195 | sta.l $00 196 | sta.b $00,X 197 | sta.w $00,X 198 | sta.l $00,X 199 | 200 | stx.b $00 201 | stx.w $00 202 | 203 | sty.b $00 204 | sty.w $00 205 | 206 | stz.b $00 207 | stz.w $00 208 | stz.b $00,X 209 | stz.w $00,X 210 | 211 | trb.b $00 212 | trb.w $00 213 | 214 | tsb.b $00 215 | tsb.w $00 216 | 217 | arch spc700 218 | adc.b A, $0000 219 | adc.w A, $0000 220 | adc.b A, $0000+X 221 | adc.w A, $0000+X 222 | 223 | and.b A, $0000 224 | and.w A, $0000 225 | and.b A, $0000+X 226 | and.w A, $0000+X 227 | 228 | asl.b $0000 229 | asl.w $0000 230 | 231 | cmp.b A, $0000 232 | cmp.w A, $0000 233 | cmp.b A, $0000+X 234 | cmp.w A, $0000+X 235 | 236 | cmp.b X, $0000 237 | cmp.w X, $0000 238 | 239 | cmp.b Y, $0000 240 | cmp.w Y, $0000 241 | 242 | dec.b $0000 243 | dec.w $0000 244 | 245 | eor.b A, $0000 246 | eor.w A, $0000 247 | eor.b A, $0000+X 248 | eor.w A, $0000+X 249 | 250 | inc.b $0000 251 | inc.w $0000 252 | 253 | lsr.b $0000 254 | lsr.w $0000 255 | 256 | mov.b A, $0000 257 | mov.w A, $0000 258 | mov.b A, $0000+X 259 | mov.w A, $0000+X 260 | 261 | mov.b X, $0000 262 | mov.w X, $0000 263 | 264 | mov.b Y, $0000 265 | mov.w Y, $0000 266 | 267 | mov.b $0000, A 268 | mov.w $0000, A 269 | mov.b $0000+X, A 270 | mov.w $0000+X, A 271 | 272 | mov.b $0000, X 273 | mov.w $0000, X 274 | 275 | mov.b $0000, Y 276 | mov.w $0000, Y 277 | 278 | or.b A, $0000 279 | or.w A, $0000 280 | or.b A, $0000+X 281 | or.w A, $0000+X 282 | 283 | rol.b $0000 284 | rol.w $0000 285 | 286 | ror.b $0000 287 | ror.w $0000 288 | 289 | sbc.b A, $0000 290 | sbc.w A, $0000 291 | sbc.b A, $0000+X 292 | sbc.w A, $0000+X 293 | 294 | 295 | adc.b A, $00 296 | adc.w A, $00 297 | adc.b A, $00+X 298 | adc.w A, $00+X 299 | 300 | and.b A, $00 301 | and.w A, $00 302 | and.b A, $00+X 303 | and.w A, $00+X 304 | 305 | asl.b $00 306 | asl.w $00 307 | 308 | cmp.b A, $00 309 | cmp.w A, $00 310 | cmp.b A, $00+X 311 | cmp.w A, $00+X 312 | 313 | cmp.b X, $00 314 | cmp.w X, $00 315 | 316 | cmp.b Y, $00 317 | cmp.w Y, $00 318 | 319 | dec.b $00 320 | dec.w $00 321 | 322 | eor.b A, $00 323 | eor.w A, $00 324 | eor.b A, $00+X 325 | eor.w A, $00+X 326 | 327 | inc.b $00 328 | inc.w $00 329 | 330 | lsr.b $00 331 | lsr.w $00 332 | 333 | mov.b A, $00 334 | mov.w A, $00 335 | mov.b A, $00+X 336 | mov.w A, $00+X 337 | 338 | mov.b X, $00 339 | mov.w X, $00 340 | 341 | mov.b Y, $00 342 | mov.w Y, $00 343 | 344 | mov.b $00, A 345 | mov.w $00, A 346 | mov.b $00+X, A 347 | mov.w $00+X, A 348 | 349 | mov.b $00, X 350 | mov.w $00, X 351 | 352 | mov.b $00, Y 353 | mov.w $00, Y 354 | 355 | or.b A, $00 356 | or.w A, $00 357 | or.b A, $00+X 358 | or.w A, $00+X 359 | 360 | rol.b $00 361 | rol.w $00 362 | 363 | ror.b $00 364 | ror.w $00 365 | 366 | sbc.b A, $00 367 | sbc.w A, $00 368 | sbc.b A, $00+X 369 | sbc.w A, $00+X 370 | -------------------------------------------------------------------------------- /src/asar-dll-bindings/c/asar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ASAR_SHARED 3 | #define expectedapiversion 303 4 | 5 | #include 6 | #include // for size_t 7 | 8 | //These structures are returned from various functions. 9 | struct errordata { 10 | const char* fullerrdata; 11 | const char* rawerrdata; 12 | const char* block; 13 | const char* filename; 14 | int line; 15 | const char* callerfilename; 16 | int callerline; 17 | int errid; 18 | }; 19 | 20 | struct labeldata { 21 | const char* name; 22 | int location; 23 | }; 24 | 25 | struct definedata { 26 | const char* name; 27 | const char* contents; 28 | }; 29 | 30 | struct writtenblockdata { 31 | int pcoffset; 32 | int snesoffset; 33 | int numbytes; 34 | }; 35 | 36 | enum mappertype { 37 | invalid_mapper, 38 | lorom, 39 | hirom, 40 | sa1rom, 41 | bigsa1rom, 42 | sfxrom, 43 | exlorom, 44 | exhirom, 45 | norom 46 | }; 47 | 48 | struct warnsetting { 49 | const char* warnid; 50 | bool enabled; 51 | }; 52 | 53 | struct memoryfile { 54 | const char* path; 55 | const void* buffer; 56 | size_t length; 57 | }; 58 | 59 | struct patchparams 60 | { 61 | // The size of this struct. Set to (int)sizeof(patchparams). 62 | int structsize; 63 | 64 | // Same parameters as asar_patch() 65 | const char* patchloc; 66 | char* romdata; 67 | int buflen; 68 | int* romlen; 69 | 70 | // Include paths to use when searching files. 71 | const char** includepaths; 72 | int numincludepaths; 73 | 74 | // should everything be reset before patching? Setting it to false will make asar 75 | // act like the currently patched file was directly appended to the previous one. 76 | // note that you can't use the previous run's defines - you can use getalldefines() 77 | // and additional_defines for that. 78 | bool should_reset; 79 | 80 | // A list of additional defines to make available to the patch. 81 | const struct definedata* additional_defines; 82 | int additional_define_count; 83 | 84 | // Path to a text file to parse standard include search paths from. 85 | // Set to NULL to not use any standard includes search paths. 86 | const char* stdincludesfile; 87 | 88 | // Path to a text file to parse standard defines from. 89 | // Set to NULL to not use any standard defines. 90 | const char* stddefinesfile; 91 | 92 | // A list of warnings to enable or disable. 93 | // Specify warnings in the format "WXXXX" where XXXX = warning ID. 94 | const struct warnsetting* warning_settings; 95 | int warning_setting_count; 96 | 97 | // List of memory files to create on the virtual filesystem. 98 | const struct memoryfile* memory_files; 99 | int memory_file_count; 100 | 101 | // Set override_checksum_gen to true and generate_checksum to true/false 102 | // to force generating/not generating a checksum. 103 | bool override_checksum_gen; 104 | bool generate_checksum; 105 | }; 106 | 107 | #ifdef __cplusplus 108 | extern "C" { 109 | #endif 110 | //Returns the version, in the format major*10000+minor*100+bugfix*1. This means that 1.2.34 would be 111 | // returned as 10234. 112 | int asar_version(void); 113 | 114 | //Returns the API version, format major*100+minor. Minor is incremented on backwards compatible 115 | // changes; major is incremented on incompatible changes. Does not have any correlation with the 116 | // Asar version. 117 | //It's not very useful directly, since asar_init() verifies this automatically. 118 | //Calling this one also sets a flag that makes asar_init not instantly return false; this is so 119 | // programs expecting an older API won't do anything unexpected. 120 | int asar_apiversion(void); 121 | 122 | //Clears out all errors, warnings and printed statements, and clears the file cache. Not really 123 | // useful, since asar_patch() already does this. 124 | bool asar_reset(void); 125 | 126 | //Applies a patch. The first argument is a filename (so Asar knows where to look for incsrc'd 127 | // stuff); however, the ROM is in memory. 128 | //This function assumes there are no headers anywhere, neither in romdata nor the sizes. romlen may 129 | // be altered by this function; if this is undesirable, set romlen equal to buflen. 130 | //The return value is whether any errors appeared (false=errors, call asar_geterrors for details). 131 | // If there is an error, romdata and romlen will be left unchanged. 132 | bool asar_patch(const char* patchloc, char* romdata, int buflen, int* romlen); 133 | 134 | // An extended version of asar_patch() with a future-proof parameter format. 135 | bool asar_patch_ex(const struct patchparams* params); 136 | 137 | //Returns the maximum possible size of the output ROM from asar_patch(). Giving this size to buflen 138 | // guarantees you will not get any buffer too small errors; however, it is safe to give smaller 139 | // buffers if you don't expect any ROMs larger than 4MB or something. 140 | int asar_maxromsize(void); 141 | 142 | //Get a list of all errors. 143 | //All pointers from these functions are valid only until the same function is called again, or until 144 | // asar_patch, asar_reset or asar_close is called, whichever comes first. Copy the contents if you 145 | // need it for a longer time. 146 | const struct errordata* asar_geterrors(int* count); 147 | 148 | //Get a list of all warnings. 149 | const struct errordata* asar_getwarnings(int* count); 150 | 151 | //Get a list of all printed data. 152 | const char* const* asar_getprints(int* count); 153 | 154 | //Get a list of all labels. 155 | const struct labeldata* asar_getalllabels(int* count); 156 | 157 | //Get the ROM location of one label. -1 means "not found". 158 | int asar_getlabelval(const char* name); 159 | 160 | //Gets the value of a define. 161 | const char* asar_getdefine(const char* name); 162 | 163 | //Gets the values and names of all defines. 164 | const struct definedata* asar_getalldefines(int* count); 165 | 166 | //Parses all defines in the parameter. The parameter controls whether it'll learn new defines in 167 | // this string if it finds any. Note that it may emit errors. 168 | const char* asar_resolvedefines(const char* data, bool learnnew); 169 | 170 | //Parses a string containing math. It automatically assumes global scope (no namespaces), and has 171 | // access to all functions and labels from the last call to asar_patch. Remember to check error to 172 | // see if it's successful (NULL) or if it failed (non-NULL, contains a descriptive string). It does 173 | // not affect asar_geterrors. 174 | double asar_math(const char* math, const char** error); 175 | 176 | //Get a list of all the blocks written to the ROM by calls such as asar_patch(). 177 | const struct writtenblockdata* asar_getwrittenblocks(int* count); 178 | 179 | //Get the mapper currently used by Asar 180 | enum mappertype asar_getmapper(void); 181 | 182 | // Generates the contents of a symbols file for in a specific format. 183 | const char* asar_getsymbolsfile(const char* format); 184 | #ifdef __cplusplus 185 | } 186 | #endif 187 | #endif 188 | -------------------------------------------------------------------------------- /tests/v140features.asm: -------------------------------------------------------------------------------- 1 | ;`89 2 | ;`AB 3 | ;`01 4 | ;`02 03 5 | ;`04 05 06 6 | ;`07 08 09 0A 7 | ;` 8 | ;`01 9 | ;`02 03 10 | ;`FF FF FF FF 11 | ;` 12 | ;`01 13 | ;`01 14 | ;`00 15 | ;`01 16 | ;`00 17 | ;` 18 | ;`01 00 00 19 | ;`02 80 80 20 | ;` 21 | ;`0A 22 | ;`0A 23 | ;`05 24 | ;`05 25 | ;`05 26 | ;`00 27 | ;`0A 28 | ;` 29 | ;`02 30 | ;`00 31 | ;` 32 | ;`BB 33 | ;`AA 34 | ;`AA 35 | ;`AA 36 | ;`AA 37 | ;` 38 | ;`01 39 | ;`00 40 | ;`01 41 | ;`00 42 | ;`00 43 | ;`01 44 | ;` 45 | ;`00 46 | ;`01 47 | ;`00 48 | ;`01 49 | ;`01 50 | ;`00 51 | ;`00 52 | ;`00 53 | ;`01 54 | ;`01 55 | ;`00 56 | ;`01 57 | ;` 58 | ;`00 59 | ;`00 60 | ;`01 61 | ;`00 62 | ;`01 63 | ;`01 64 | ;`01 65 | ;`01 66 | ;`00 67 | ;`01 68 | ;`00 69 | ;`00 70 | ;`00 71 | ;`01 72 | ;`00 73 | ;` 74 | ;`01 75 | ;` 76 | ;`02 77 | ;` 78 | ;`05 79 | ;`04 80 | ;`03 81 | ;`02 82 | ;`01 83 | ;` 84 | ;`03 85 | ;`02 86 | ;`01 87 | ;` 88 | ;`07 89 | ;`06 90 | ;`05 91 | ;`04 92 | ;`03 93 | ;`02 94 | ;`01 95 | ;` 96 | ;`00 00 97 | ;`00 01 98 | ;`00 02 99 | ;`00 03 100 | ;`00 04 101 | ;`00 05 102 | ;`00 06 103 | ;`00 07 104 | ;`00 08 105 | ;`00 09 106 | ;`01 00 107 | ;`01 01 108 | ;`01 02 109 | ;`01 03 110 | ;`01 04 111 | ;`01 05 112 | ;`01 06 113 | ;`01 07 114 | ;`01 08 115 | ;`01 09 116 | ;`02 00 117 | ;`02 01 118 | ;`02 02 119 | ;`02 03 120 | ;`02 04 121 | ;`02 05 122 | ;`02 06 123 | ;`02 07 124 | ;`02 08 125 | ;`02 09 126 | ;`03 00 127 | ;`03 01 128 | ;`03 02 129 | ;`03 03 130 | ;`03 04 131 | ;`03 05 132 | ;`03 06 133 | ;`03 07 134 | ;`03 08 135 | ;`03 09 136 | ;`04 00 137 | ;`04 01 138 | ;`04 02 139 | ;`04 03 140 | ;`04 04 141 | ;`04 05 142 | ;`04 06 143 | ;`04 07 144 | ;`04 08 145 | ;`04 09 146 | ;`05 00 147 | ;`05 01 148 | ;`05 02 149 | ;`05 03 150 | ;`05 04 151 | ;`05 05 152 | ;`05 06 153 | ;`05 07 154 | ;`05 08 155 | ;`05 09 156 | ;`06 00 157 | ;`06 01 158 | ;`06 02 159 | ;`06 03 160 | ;`06 04 161 | ;`06 05 162 | ;`06 06 163 | ;`06 07 164 | ;`06 08 165 | ;`06 09 166 | ;`07 00 167 | ;`07 01 168 | ;`07 02 169 | ;`07 03 170 | ;`07 04 171 | ;`07 05 172 | ;`07 06 173 | ;`07 07 174 | ;`07 08 175 | ;`07 09 176 | ;`08 00 177 | ;`08 01 178 | ;`08 02 179 | ;`08 03 180 | ;`08 04 181 | ;`08 05 182 | ;`08 06 183 | ;`08 07 184 | ;`08 08 185 | ;`08 09 186 | ;`09 00 187 | ;`09 01 188 | ;`09 02 189 | ;`09 03 190 | ;`09 04 191 | ;`09 05 192 | ;`09 06 193 | ;`09 07 194 | ;`09 08 195 | ;`09 09 196 | ;` 197 | ;`AC 198 | ;`65 199 | ;` 200 | ;`0B 201 | ;` 202 | ;`0F 203 | ;` 204 | ;`0A 205 | ;`0B 206 | ;`warnWfeature_deprecated 207 | ;` 208 | ;P> 209 | ;P>;This is not a comment, so getconnectedlines() should ignore it and not remove it. 210 | ;P> 211 | ;P>Let's have some random decimal number with fractional part: 10.34017 212 | ;P>Now the same number, but with a different precision: 10.3401734476 213 | ;P>Testing a few more numbers: 0, 0.1, -0.1, 1, -1 214 | ;P> 215 | asar 1.90 216 | 217 | org $008000 218 | 219 | db readfile1("data/64kb.bin", 0) 220 | db readfile1("data/64kb.bin", 1) 221 | db readfile1("data/filename with spaces.bin", 0) 222 | dw readfile2("data/filename with spaces.bin", 1) 223 | dl readfile3("data/filename with spaces.bin", 3) 224 | dd readfile4("data/filename with spaces.bin", 6) 225 | 226 | db readfile1("data/filename with spaces.bin", 0, 1000) 227 | dw readfile2("data/filename with spaces.bin", 1, -1000) 228 | dd readfile4("data/filename with spaces.bin", 14, $FFFFFFFF) 229 | 230 | db canreadfile1("data/filename with spaces.bin", 0) 231 | db canreadfile2("data/filename with spaces.bin", 1) 232 | db canreadfile4("data/filename with spaces.bin", 14) 233 | db canreadfile("data/filename with spaces.bin", 0, 16) 234 | db canreadfile("data/filename with spaces.bin", 0, 17) 235 | 236 | dl snestopc($008001) 237 | dl pctosnes($000002) 238 | 239 | db max(5, 10) 240 | db max(10, 5) 241 | db min(5, 10) 242 | db min(10, 5) 243 | db clamp(5, 0, 10) 244 | db clamp(-1, 0, 10) 245 | db clamp(11, 0, 10) 246 | 247 | db safediv(32, 16, 0) 248 | db safediv(32, 0, 0) 249 | 250 | db select(0, $AA, $BB) 251 | db select(1, $AA, $BB) 252 | db select(0.1, $AA, $BB) 253 | db select(-1, $AA, $BB) 254 | db select(-0.1, $AA, $BB) 255 | 256 | db not(0) 257 | db not(1) 258 | db equal(1, 1) 259 | db equal(0, 1) 260 | db notequal(1, 1) 261 | db notequal(0, 1) 262 | 263 | db less(0, 0) 264 | db less(0, 1) 265 | db less(1, 0) 266 | db lessequal(0, 0) 267 | db lessequal(0, 1) 268 | db lessequal(1, 0) 269 | db greater(0, 0) 270 | db greater(0, 1) 271 | db greater(1, 0) 272 | db greaterequal(0, 0) 273 | db greaterequal(0, 1) 274 | db greaterequal(1, 0) 275 | 276 | db and(0, 0) 277 | db and(0, 1) 278 | db and(1, 1) 279 | db or(0, 0) 280 | db or(0, 1) 281 | db or(1, 1) 282 | db nand(0, 0) 283 | db nand(0, 1) 284 | db nand(1, 1) 285 | db nor(0, 0) 286 | db nor(0, 1) 287 | db nor(1, 1) 288 | db xor(0, 0) 289 | db xor(0, 1) 290 | db xor(1, 1) 291 | 292 | !testlabel = 1 293 | !anothertestlabel = 2 294 | 295 | if !testlabel == 0 296 | db $00 297 | elseif !testlabel == 1 && !anothertestlabel == 2 298 | db $01 299 | elseif !testlabel == 2 && !anothertestlabel == 1 300 | db $02 301 | elseif !testlabel == 3 && !anothertestlabel == 0 302 | db $03 303 | else 304 | db $FF 305 | 306 | while !testlabel > 0 307 | db $0A 308 | endif 309 | endif 310 | 311 | !mathlabel #= 0.01+0.01 312 | !mathlabel #= !mathlabel*100 313 | db !mathlabel 314 | 315 | !whiletestvar = 5 316 | 317 | while !whiletestvar > 0 318 | db !whiletestvar 319 | !whiletestvar #= !whiletestvar-1 320 | endif 321 | 322 | macro whilemacro1(numloops) 323 | !loopdyloop = 324 | while !loopdyloop > 0 325 | db !loopdyloop 326 | !loopdyloop #= !loopdyloop-1 327 | endif 328 | endmacro 329 | 330 | macro whilemacro2() 331 | %whilemacro1(7) 332 | endmacro 333 | 334 | %whilemacro1(3) 335 | %whilemacro2() 336 | 337 | 338 | !cond1 = 0 339 | 340 | while !cond1 < 10 341 | !cond2 = 0 342 | 343 | while !cond2 < 10 344 | db !cond1 345 | db !cond2 346 | !cond2 #= !cond2+1 347 | endif 348 | 349 | !cond1 #= !cond1+1 350 | endif 351 | 352 | 353 | db round(1.719247114, 2)*100 354 | db round(100.6414710, 0) 355 | 356 | 357 | function multilinefunction(x) = x+\ ;;;;; This is a comment, getconnectedlines() should remove it 358 | 10 359 | 360 | db multilinefunction(1) 361 | 362 | 363 | macro yetanothermacro() 364 | db \ 365 | $0F 366 | endmacro 367 | 368 | %yetanothermacro() 369 | 370 | 371 | db $0A ; This is a comment as well, so getconnectedlines() should remove it and ignore this backslah right here -> \ 372 | db $0B 373 | 374 | 375 | print "" 376 | print ";This is not a comment, ",\ 377 | "so getconnectedlines() should ignore it and not remove it." 378 | 379 | print "" 380 | 381 | print "Let's have some random decimal number with fractional part: ",double(10.340173447601384024017510834015701571048) 382 | print "Now the same number, but with a different precision: ",double(10.340173447601384024017510834015701571048, 10) 383 | print "Testing a few more numbers: ",double(0.0),", ",double(0.1),", ",double(-0.1),", ",double(1.0),", ",double(-1.0) 384 | 385 | print "" 386 | -------------------------------------------------------------------------------- /src/asar/crc32.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic crc32 helper function 3 | */ 4 | 5 | #include "crc32.h" 6 | #include 7 | 8 | /* The implementation here was originally done by Gary S. Brown. I have 9 | borrowed the tables directly, and made some minor changes to the 10 | crc32-function (including changing the interface). //ylo */ 11 | 12 | /* ============================================================= */ 13 | /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ 14 | /* code or tables extracted from it, as desired without restriction. */ 15 | /* */ 16 | /* First, the polynomial itself and its table of feedback terms. The */ 17 | /* polynomial is */ 18 | /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ 19 | /* */ 20 | /* Note that we take it "backwards" and put the highest-order term in */ 21 | /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ 22 | /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ 23 | /* the MSB being 1. */ 24 | /* */ 25 | /* Note that the usual hardware shift register implementation, which */ 26 | /* is what we're using (we're merely optimizing it by doing eight-bit */ 27 | /* chunks at a time) shifts bits into the lowest-order term. In our */ 28 | /* implementation, that means shifting towards the right. Why do we */ 29 | /* do it this way? Because the calculated CRC must be transmitted in */ 30 | /* order from highest-order term to lowest-order term. UARTs transmit */ 31 | /* characters in order from LSB to MSB. By storing the CRC this way, */ 32 | /* we hand it to the UART in the order low-byte to high-byte; the UART */ 33 | /* sends each low-bit to hight-bit; and the result is transmission bit */ 34 | /* by bit from highest- to lowest-order term without requiring any bit */ 35 | /* shuffling on our part. Reception works similarly. */ 36 | /* */ 37 | /* The feedback terms table consists of 256, 32-bit entries. Notes: */ 38 | /* */ 39 | /* The table can be generated at runtime if desired; code to do so */ 40 | /* is shown later. It might not be obvious, but the feedback */ 41 | /* terms simply represent the results of eight shift/xor opera- */ 42 | /* tions for all combinations of data and CRC register values. */ 43 | /* */ 44 | /* The values must be right-shifted by eight bits by the "updcrc" */ 45 | /* logic; the shift must be unsigned (bring in zeroes). On some */ 46 | /* hardware you could probably optimize the shift in assembler by */ 47 | /* using byte-swap instructions. */ 48 | /* polynomial $edb88320 */ 49 | /* */ 50 | /* -------------------------------------------------------------------- */ 51 | 52 | static uint32_t crc32_tab[] = { 53 | 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 54 | 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 55 | 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 56 | 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 57 | 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 58 | 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 59 | 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 60 | 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 61 | 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 62 | 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 63 | 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 64 | 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 65 | 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 66 | 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 67 | 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 68 | 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 69 | 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 70 | 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 71 | 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 72 | 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 73 | 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 74 | 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 75 | 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 76 | 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 77 | 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 78 | 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 79 | 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 80 | 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 81 | 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 82 | 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 83 | 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 84 | 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 85 | 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 86 | 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 87 | 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 88 | 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 89 | 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 90 | 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 91 | 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 92 | 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 93 | 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 94 | 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 95 | 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 96 | 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 97 | 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 98 | 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 99 | 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 100 | 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 101 | 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 102 | 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 103 | 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 104 | 0x2d02ef8dL 105 | }; 106 | 107 | /* Return a 32-bit CRC of the contents of the buffer. */ 108 | 109 | uint32_t crc32(const uint8_t *s, unsigned int len) 110 | { 111 | unsigned int i; 112 | uint32_t crc32val; 113 | 114 | crc32val = (uint32_t)~0; 115 | for (i = 0; i < len; i ++) 116 | { 117 | crc32val = 118 | crc32_tab[(crc32val ^ s[i]) & 0xff] ^ 119 | (crc32val >> 8); 120 | } 121 | return ~crc32val; 122 | } 123 | 124 | 125 | -------------------------------------------------------------------------------- /ext/notepad-plus-plus/syntax-highlighting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 00; 01 02 03 04 9 | % $ 10 | $ % 11 | A B C D E F a b c d e f 12 | 13 | 14 | 15 | 16 | == != >= <= > < = + - * / << >> | & ~ ^ ( ) , : -> && || ?= # [ ] . \ 17 | 18 | { 19 | 20 | } 21 | macro if while struct for 22 | else elseif 23 | endmacro endif endstruct endwhile endfor 24 | 25 | 26 | 27 | ! ? 28 | @ 29 | lorom hirom exlorom exhirom sa1rom fullsa1rom sfxrom norom macro endmacro incbin incsrc fillbyte fillword filllong filldword fill pad padbyte padword padlong paddword table cleartable ltr rtl skip namespace import print org warnpc base on off reset bytes freespaceuse pc hex freespace freecode freedata ram noram align cleaned static autoclean autoclear prot pushpc pullpc pushbase pullbase function if else elseif endif assert arch 65816 spc700 spc700-inline superfx math pri round warn xkas bank noassume auto asar include includefrom includeonce error warn skip double round pushtable pulltable undef extends check title nested bankcross warnings push pull disable enable global 30 | db dw dl dd adc and asl bcc blt bcs bge beq bit bmi bne bpl bra brk brl bvc bvs clc cld cli clv cmp cop cpx cpy dec dea dex dey eor inc ina inx iny jmp jml jsr jsl lda ldx ldy lsr mvn mvp nop ora pea pei per pha phb phd phk php phx phy pla plb pld plp plx ply rep rol ror rti rtl rts sbc sec sed sei sep sta stp stx sty stz tax tay tcd tcs tdc trb tsc tsb tsx txa txs txy tya tyx wai wdm xba xce s x y b w l a r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 add alt1 alt2 alt3 asr bic cache cmode color div2 fmult from getb getbh getbl getbs getc hib ibt iwt ldb ldw link ljmp lm lms lmult lob loop merge mult not or plot ramb romb rpix sbk sex sm sms stb stop stw sub swap to umult with xor addw ya and1 c bbc0 bbc1 bbc2 bbc3 bbc4 bbc5 bbc6 bbc7 bbs0 bbs1 bbs2 bbs3 bbs4 bbs5 bbs6 bbs7 call cbne clr0 clr1 clr2 clr3 clr4 clr5 clr6 clr7 clrc clrp clrv cmpw daa das dbnz decw di div ei eor1 incw mov sp mov1 movw mul not1 notc or1 pcall pop p push ret reti set0 set1 set2 set3 set4 set5 set6 set7 setc setp sleep subw tcall tclr tset xcn lea move moves moveb movew 31 | read1 read2 read3 read4 canread1 canread2 canread4 sqrt sin cos tan asin acos atan arcsin arccos arctan log log10 log2 _read1 _read2 _read3 _read4 _canread1 _canread2 _canread4 _sqrt _sin _cos _tan _asin _acos _atan _arcsin _arccos _arctan _log _log10 _log2 readfile1 _readfile1 readfile2 _readfile2 readfile3 _readfile3 readfile4 _readfile4 canreadfile1 _canreadfile1 canreadfile2 _canreadfile2 canreadfile3 _canreadfile3 canreadfile4 _canreadfile4 canreadfile _canreadfile snestopc _snestopc pctosnes _pctosnes max _max min _min clamp _clamp safediv _safediv select _select not _not equal _equal notequal _notequal less _less lessequal _lessequal greater _greater greaterequal _greaterequal and _and or _or nand _nand nor _nor xor _xor defined _defined filesize _filesize getfilestatus _getfilestatus sizeof _sizeof objectsize _objectsize stringsequal _stringsequal stringsequalnocase _stringsequalnocase 32 | % 33 | 34 | 35 | 00" 01 02" 03' 04 05' 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/asar/platform/file-helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "platform/file-helpers.h" 2 | 3 | 4 | // This function is based in part on nall, which is under the following licence. 5 | // This modified version is licenced under the LGPL version 3 or later. See the LICENSE file 6 | // for details. 7 | // 8 | // Copyright (c) 2006-2015 byuu 9 | // 10 | // Permission to use, copy, modify, and/or distribute this software for 11 | // any purpose with or without fee is hereby granted, provided that the 12 | // above copyright notice and this permission notice appear in all 13 | // copies. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 16 | // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 17 | // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 18 | // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 19 | // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 20 | // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 | // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 | // PERFORMANCE OF THIS SOFTWARE. 23 | string dir(char const *name) 24 | { 25 | for (signed i = (int)strlen(name); i >= 0; i--) 26 | { 27 | if (name[i] == '/' || name[i] == '\\') 28 | { 29 | return string(name, i+1); 30 | } 31 | } 32 | return ""; 33 | } 34 | 35 | string create_combined_path(const char* path1, const char* path2) 36 | { 37 | string combined = path1; 38 | 39 | int length = combined.length(); 40 | 41 | if (combined.length() > 0 && path1[length - 1] != '\\' && path1[length - 1] != '/') 42 | { 43 | combined += get_native_path_separator(); 44 | } 45 | 46 | combined += path2; 47 | 48 | return normalize_path(combined); 49 | } 50 | 51 | 52 | // RPG Hacker: This function attempts to normalize a path. 53 | // This means that it attempts to put it into a format 54 | // where a simple string compare between two paths 55 | // referring to the same file will hopefully always 56 | // succeed. 57 | // There are a few known problems and limitations: 58 | // - Relative paths are not recommended, as they can't be 59 | // resolved reliably. For example, in this path 60 | // ../patch/main.asm 61 | // we can't collapse the .. because we don't know the 62 | // parent directory. A comparison will also fail when 63 | // one piece of code uses a relative path while another 64 | // piece of code uses an absolute path. For those 65 | // reasons, it's recommended to always use absolute paths 66 | // everywhere if possible. 67 | // - Windows network paths like 68 | // \\MY_PC\patch\main.asm 69 | // Will likely break with this, since the function converts 70 | // all back slashes to forward slashes. I think Windows 71 | // actually requires back slashes for network paths. 72 | // - Currently, the code doesn't look at drive letters 73 | // and just treats them as folders, so a path like 74 | // C:/../patch/main.asm 75 | // would result in 76 | // patch/main.asm 77 | // (However, a path like that is invalid, anyways, so 78 | // this hopefully doesn't matter). 79 | string normalize_path(const char* path) 80 | { 81 | string normalized = path; 82 | 83 | 84 | // RPG Hacker: Replace all \ in path by / 85 | // (Windows should work with / in paths just fine). 86 | // Note: will likely break network paths on Windows, 87 | // which still expect a prefix of \\, but does anyone 88 | // seriously even use them with Asar? 89 | for (int i = 0; i < normalized.length(); ++i) 90 | { 91 | if (normalized[i] == '\\') 92 | { 93 | normalized.temp_raw()[i]= '/'; 94 | } 95 | } 96 | 97 | // RPG Hacker: Collapse path by removing all unnecessary 98 | // . or .. path components. 99 | // As a little hack, just overwrite all the stuff we're 100 | // going to remove with 0x01 and remove it later. Probably 101 | // easier than to always shorten the path immediately. 102 | // Also using \x01 instead of \0 so that the path is still 103 | // easily readable in a debugger (since it normally just 104 | // assumes a string to end at \0). I don't think \x01 can 105 | // be used in valid paths, so this should be okay. 106 | char* previous_dir_start_pos = nullptr; 107 | char* current_dir_start_pos = normalized.temp_raw(); 108 | while (*current_dir_start_pos == '/') 109 | { 110 | ++current_dir_start_pos; 111 | } 112 | char* current_dir_end_pos = current_dir_start_pos; 113 | 114 | 115 | while (*current_dir_start_pos != '\0') 116 | { 117 | while (*current_dir_end_pos != '/' && *current_dir_end_pos != '\0') 118 | { 119 | ++current_dir_end_pos; 120 | } 121 | 122 | size_t length = (size_t)(current_dir_end_pos - current_dir_start_pos); 123 | if (length > 0 && strncmp(current_dir_start_pos, ".", length) == 0) 124 | { 125 | // Found a . path component - remove it. 126 | while (current_dir_start_pos != current_dir_end_pos) 127 | { 128 | *current_dir_start_pos = '\x01'; 129 | ++current_dir_start_pos; 130 | } 131 | 132 | if (*current_dir_start_pos == '/') 133 | { 134 | *current_dir_start_pos = '\x01'; 135 | ++current_dir_end_pos; 136 | } 137 | } 138 | else if (length > 0 && strncmp(current_dir_start_pos, "..", length) == 0) 139 | { 140 | // Found a .. path component - if we have any known 141 | // folder before it, remove them both. 142 | if (previous_dir_start_pos != nullptr) 143 | { 144 | // previous_dir_start_pos and current_dir_start_pos are immediately 145 | // set to something else shortly after, so it should be 146 | // okay to move them directly here and not use a 147 | // temporary variable. 148 | while (*previous_dir_start_pos != '/' && *previous_dir_start_pos != '\0') 149 | { 150 | *previous_dir_start_pos = '\x01'; 151 | ++previous_dir_start_pos; 152 | } 153 | 154 | if (*previous_dir_start_pos == '/') 155 | { 156 | *previous_dir_start_pos = '\x01'; 157 | } 158 | 159 | while (current_dir_start_pos != current_dir_end_pos) 160 | { 161 | *current_dir_start_pos = '\x01'; 162 | ++current_dir_start_pos; 163 | } 164 | 165 | if (*current_dir_start_pos == '/') 166 | { 167 | *current_dir_start_pos = '\x01'; 168 | ++current_dir_end_pos; 169 | } 170 | } 171 | 172 | previous_dir_start_pos = nullptr; 173 | } 174 | else 175 | { 176 | if (*current_dir_end_pos == '/') 177 | { 178 | ++current_dir_end_pos; 179 | } 180 | 181 | if (length > 0) 182 | { 183 | previous_dir_start_pos = current_dir_start_pos; 184 | } 185 | } 186 | 187 | current_dir_start_pos = current_dir_end_pos; 188 | } 189 | 190 | 191 | // Now construct our new string by copying everything but the \x01 into it. 192 | string copy; 193 | 194 | for (int i = 0; i < normalized.length(); ++i) 195 | { 196 | if (normalized[i] != '\x01') 197 | { 198 | copy += normalized[i]; 199 | } 200 | } 201 | 202 | normalized = copy; 203 | 204 | 205 | // RPG Hacker: On Windows, file paths are case-insensitive. 206 | // It isn't really good style to mix different cases, especially 207 | // when referring to the same file, but it's theoretically possible 208 | // to do so, so we need to handle it and not have Asar fail in this case. 209 | // The easiest way to handle it is to convert the entire path to lowercase. 210 | #if defined(windows) 211 | normalized = lower(normalized); 212 | #endif 213 | 214 | 215 | // TODO: Maybe resolve symbolic links here? 216 | // Not sure if it's a good idea and if it's needed in the first place. 217 | // In theory, it could lead to some problems with files that exist 218 | // only in memory. 219 | return normalized; 220 | } 221 | 222 | string get_base_name(char const *name) 223 | { 224 | for(int i = (int)strlen(name); i >= 0; --i) 225 | { 226 | if(name[i] == '/' || name[i] == '\\') 227 | { 228 | //file has no extension 229 | break; 230 | } 231 | if(name[i] == '.') 232 | { 233 | return string(name, i); 234 | } 235 | } 236 | return string(name); 237 | } 238 | -------------------------------------------------------------------------------- /docs/shared/highlight_js_asar/highlight_js_asar.js: -------------------------------------------------------------------------------- 1 | hljsAsar = { 2 | init : function() 3 | { 4 | hljs.registerLanguage("powershell", function(hljs) 5 | { 6 | return { 7 | aliases: ["ps"], 8 | case_insensitive: true, 9 | keywords: 10 | { 11 | $pattern: /-?[A-z\.\-]+/ 12 | } 13 | } 14 | }); 15 | 16 | // I know this is ugly, but I don't know how else to solve Asar's label rules... 17 | const asarOpcodes = ["db", "dw", "dl", "dd", "adc", "and", "asl", "bcc", "blt", "bcs", "bge", "beq", "bit", "bmi", "bne", "bpl", "bra", "brk", "brl", "bvc", "bvs", "clc", "cld", "cli", "clv", "cmp", "cop", "cpx", "cpy", "dec", "dea", "dex", "dey", "eor", "inc", "ina", "inx", "iny", "jmp", "jml", "jsr", "jsl", "lda", "ldx", "ldy", "lsr", "mvn", "mvp", "nop", "ora", "pea", "pei", "per", "pha", "phb", "phd", "phk", "php", "phx", "phy", "pla", "plb", "pld", "plp", "plx", "ply", "rep", "rol", "ror", "rti", "rtl", "rts", "sbc", "sec", "sed", "sei", "sep", "sta", "stp", "stx", "sty", "stz", "tax", "tay", "tcd", "tcs", "tdc", "trb", "tsc", "tsb", "tsx", "txa", "txs", "txy", "tya", "tyx", "wai", "wdm", "xba", "xce", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "add", "alt1", "alt2", "alt3", "asr", "bic", "cache", "cmode", "color", "div2", "fmult", "from", "getb", "getbh", "getbl", "getbs", "getc", "hib", "ibt", "iwt", "ldb", "ldw", "link", "ljmp", "lm", "lms", "lmult", "lob", "loop", "merge", "mult", "not", "or", "plot", "ramb", "romb", "rpix", "sbk", "sex", "sm", "sms", "stb", "stop", "stw", "sub", "swap", "to", "umult", "with", "xor", "addw", "ya", "and1", "bbc0", "bbc1", "bbc2", "bbc3", "bbc4", "bbc5", "bbc6", "bbc7", "bbs0", "bbs1", "bbs2", "bbs3", "bbs4", "bbs5", "bbs6", "bbs7", "call", "cbne", "clr0", "clr1", "clr2", "clr3", "clr4", "clr5", "clr6", "clr7", "clrc", "clrp", "clrv", "cmpw", "daa", "das", "dbnz", "decw", "di", "div", "ei", "eor1", "incw", "mov", "sp", "mov1", "movw", "mul", "not1", "notc", "or1", "pcall", "pop", "push", "ret", "reti", "set0", "set1", "set2", "set3", "set4", "set5", "set6", "set7", "setc", "setp", "sleep", "subw", "tcall", "tclr", "tset", "xcn", "lea", "move", "moves", "moveb", "movew"]; 18 | 19 | const asarKeywords = ["lorom", "hirom", "exlorom", "exhirom", "sa1rom", "fullsa1rom", "sfxrom", "norom", "macro", "endmacro", "struct", "endstruct", "extends", "incbin", "incsrc", "fillbyte", "fillword", "filllong", "filldword", "fill", "padbyte", "pad", "padword", "padlong", "paddword", "table", "cleartable", "ltr", ",rtl", "skip", "namespace", "import", "print", "org", "warnpc", "base", "on", "off", "reset", "freespaceuse", "pc", "bytes", "hex", "freespace", "freecode", "freedata", "ram", "noram", "align", "cleaned", "static", "autoclean", "autoclear", "prot", "pushpc", "pullpc", "pushbase", "pullbase", "function", "if", "else", "elseif", "endif", "while", "endwhile", "for", "endfor", "assert", "arch", "65816", "spc700", "inline", "superfx", "math", "pri", "round", "xkas", "bankcross", "bank", "noassume", "auto", "asar", "includefrom", "includeonce", "include", "error", "skip", "double", "round", "pushtable", "pulltable", "undef", "check", "title", "nested", "warnings", "push", "pull", "disable", "enable", "warn", "address", "dpbase", "optimize", "dp", "none", "always", "default", "mirrors", "global", "spcblock", "endspcblock", "nspc", "execute", "\\.\\."]; 20 | 21 | const asarIntrinsicFunctions = ["read1", "read2", "read3", "read4", "canread1", "canread2", "canread4", "sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "arcsin", "arccos", "arctan", "log", "log10", "log2", "_read1", "_read2", "_read3", "_read4", "_canread1", "_canread2", "_canread4", "_sqrt", "_sin", "_cos", "_tan", "_asin", "_acos", "_atan", "_arcsin", "_arccos", "_arctan", "_log", "_log10", "_log2", "readfile1", "_readfile1", "readfile2", "_readfile2", "readfile3", "_readfile3", "readfile4", "_readfile4", "canreadfile1", "_canreadfile1", "canreadfile2", "_canreadfile2", "canreadfile3", "_canreadfile3", "canreadfile4", "_canreadfile4", "canreadfile", "_canreadfile", "filesize", "_filesize", "getfilestatus", "_getfilestatus", "snestopc", "_snestopc", "pctosnes", "_pctosnes", "max", "_max", "min", "_min", "clamp", "_clamp", "safediv", "_safediv", "select", "_select", "not", "_not", "equal", "_equal", "notequal", "_notequal", "less", "_less", "lessequal", "_lessequal", "greater", "_greater", "greaterequal", "_greaterequal", "and", "_and", "or", "_or", "nand", "_nand", "nor", "_nor", "xor", "_xor", "defined", "_defined", "sizeof", "_sizeof", "objectsize", "_objectsize", "stringsequal", "_stringsequal", "stringsequalnocase", "_stringsequalnocase"]; 22 | 23 | const asarNumberLiteralsMode = 24 | { 25 | scope: "number", 26 | variants: 27 | [ 28 | { 29 | begin: /(?<=\W|^)#?[+\-~]?0x[0-9a-fA-F]+(?=\W|$)/ 30 | }, 31 | { 32 | begin: /(?<=\W|^)#?[+\-~]?[0-9]+(\.[0-9]+)?(?=\W|$)/ 33 | }, 34 | { 35 | begin: /(?<=\W|^)#?[+\-~]?%[0-1]+(?=\W|$)/ 36 | }, 37 | { 38 | begin: /(?<=\W|^)#?[+\-~]?\$[0-9a-fA-F]+(?=\W|$)/ 39 | }/*, 40 | { 41 | begin: /(?<=\W|^)#?(\(|\)|\+|\-|\*|\/|\%|\<\<|\>\>|\&|\||\^|\~|\*\*)+/ 42 | }*/ 43 | ], 44 | relevance: 0 45 | }; 46 | 47 | const asarLabelsMode = 48 | { 49 | scope: "label", 50 | variants: 51 | [ 52 | { 53 | begin: /#?\??\.*[a-zA-Z0-9_]+:?/ 54 | }, 55 | { 56 | begin: /\??(-+|\++):?/ 57 | } 58 | ], 59 | relevance: 0 60 | } 61 | 62 | hljs.registerLanguage("65c816_asar", 63 | function(hljs) 64 | { 65 | return { 66 | case_insensitive: true, 67 | aliases: ["asar"], 68 | keywords: 69 | { 70 | opcodes: asarOpcodes.join(' '), 71 | keywords: asarKeywords.join(' '), 72 | builtin: asarIntrinsicFunctions.join(' '), 73 | $pattern: hljs.IDENT_RE 74 | }, 75 | contains: 76 | [ 77 | hljs.COMMENT("[;]", "$"), 78 | hljs.C_BLOCK_COMMENT_MODE, 79 | hljs.QUOTE_STRING_MODE, 80 | hljs.APOS_STRING_MODE, 81 | { 82 | scope: "special", 83 | begin: /\s*^@/, 84 | end: /$/, 85 | relevance: 0 86 | }, 87 | { 88 | scope: "keywords", 89 | begin: asarKeywords.join('\\b|').concat('\\b') 90 | }, 91 | asarNumberLiteralsMode, 92 | { 93 | scope: "builtin", 94 | begin: "(" + asarIntrinsicFunctions.join('|') + ")\\(", 95 | end: "\\)", 96 | contains: 97 | [ 98 | hljs.QUOTE_STRING_MODE, 99 | hljs.APOS_STRING_MODE, 100 | asarNumberLiteralsMode, 101 | 'self', 102 | asarLabelsMode 103 | ], 104 | }, 105 | { 106 | scope: "function", 107 | variants: 108 | [ 109 | { 110 | // RPG Hacker: The exclamation mark here is for the case when defines are used as functions. 111 | // Probably not a very common case, but my VWF Dialogues Patch uses it a lot, and this makes 112 | // stuff a lot more readable in those cases. 113 | begin: /(?:%|!)?[a-zA-Z0-9_]+\(/, 114 | end: /\)/ 115 | } 116 | ], 117 | contains: 118 | [ 119 | hljs.QUOTE_STRING_MODE, 120 | hljs.APOS_STRING_MODE, 121 | asarNumberLiteralsMode, 122 | 'self', 123 | asarLabelsMode 124 | ], 125 | relevance: 0 126 | }, 127 | { 128 | scope: "define", 129 | variants: 130 | [ 131 | { 132 | begin: /!\^*[a-zA-Z0-9_{}]+/ 133 | }, 134 | { 135 | begin: /<\^*[a-zA-Z0-9_]+>/ 136 | }, 137 | ], 138 | relevance: 10 139 | }, 140 | { 141 | scope: "opcodes", 142 | begin: asarOpcodes.join('(\\.[bwl]|\\b)|').concat('(\\.[bwl]|\\b)') 143 | }, 144 | asarLabelsMode 145 | ], 146 | i: "/" 147 | } 148 | } 149 | ); 150 | } 151 | }; -------------------------------------------------------------------------------- /src/asar/virtualfile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "virtualfile.h" 3 | #include "platform/file-helpers.h" 4 | #include "warnings.h" 5 | 6 | 7 | 8 | class virtual_file 9 | { 10 | public: 11 | virtual ~virtual_file() 12 | { 13 | } 14 | 15 | virtual void close() = 0; 16 | 17 | virtual size_t read(void* out_buffer, size_t pos, size_t num_bytes) = 0; 18 | 19 | virtual size_t get_size() = 0; 20 | }; 21 | 22 | class memory_file : public virtual_file 23 | { 24 | public: 25 | memory_file(const void* data, size_t length) 26 | : m_data(data), m_length(length) 27 | { 28 | } 29 | 30 | virtual ~memory_file() 31 | { 32 | close(); 33 | } 34 | 35 | virtual void close() 36 | { 37 | } 38 | 39 | virtual size_t read(void* out_buffer, size_t pos, size_t num_bytes) 40 | { 41 | if(pos > m_length) return 0; 42 | 43 | int diff = (int)(pos + num_bytes) - (int)m_length; 44 | num_bytes -= diff < 0 ? 0 : (unsigned int)diff; 45 | 46 | memcpy(out_buffer, (const char*)m_data + pos, num_bytes); 47 | return num_bytes; 48 | } 49 | 50 | virtual size_t get_size() 51 | { 52 | return m_length; 53 | } 54 | 55 | private: 56 | const void* m_data; 57 | size_t m_length; 58 | }; 59 | 60 | class physical_file : public virtual_file 61 | { 62 | public: 63 | physical_file() 64 | : m_file_handle(nullptr) 65 | { 66 | } 67 | 68 | virtual ~physical_file() 69 | { 70 | close(); 71 | } 72 | 73 | virtual_file_error open(const string& path) 74 | { 75 | if (path != "") 76 | { 77 | // randomdude999: checking this before file regularity to improve error messages 78 | if(!file_exists((const char*)path)) return vfe_doesnt_exist; 79 | if(!check_is_regular_file((const char*)path)) return vfe_not_regular_file; 80 | 81 | m_file_handle = fopen((const char*)path, "rb"); 82 | 83 | if (m_file_handle == nullptr) 84 | { 85 | if (errno == ENOENT) 86 | { 87 | return vfe_doesnt_exist; 88 | } 89 | else if (errno == EACCES) 90 | { 91 | return vfe_access_denied; 92 | } 93 | else 94 | { 95 | return vfe_unknown; 96 | } 97 | } 98 | 99 | return vfe_none; 100 | } 101 | 102 | return vfe_doesnt_exist; 103 | } 104 | 105 | virtual void close() 106 | { 107 | if (m_file_handle != nullptr) 108 | { 109 | fclose(m_file_handle); 110 | m_file_handle = nullptr; 111 | } 112 | } 113 | 114 | virtual size_t read(void* out_buffer, size_t pos, size_t num_bytes) 115 | { 116 | fseek(m_file_handle, (long)pos, SEEK_SET); 117 | return fread(out_buffer, 1, num_bytes, m_file_handle); 118 | } 119 | 120 | virtual size_t get_size() 121 | { 122 | fseek(m_file_handle, 0, SEEK_END); 123 | long filepos = ftell(m_file_handle); 124 | fseek(m_file_handle, 0, SEEK_SET); 125 | 126 | return (size_t)filepos; 127 | } 128 | 129 | private: 130 | friend class virtual_filesystem; 131 | 132 | FILE* m_file_handle; 133 | }; 134 | 135 | 136 | 137 | void virtual_filesystem::initialize(const char** include_paths, size_t num_include_paths) 138 | { 139 | m_include_paths.reset(); 140 | 141 | for (size_t i = 0; i < num_include_paths; ++i) 142 | { 143 | m_include_paths[(int)i] = include_paths[i]; 144 | } 145 | 146 | m_last_error = vfe_none; 147 | m_memory_files.reset(); 148 | } 149 | 150 | void virtual_filesystem::destroy() 151 | { 152 | m_include_paths.reset(); 153 | } 154 | 155 | 156 | virtual_file_handle virtual_filesystem::open_file(const char* path, const char* base_path) 157 | { 158 | m_last_error = vfe_none; 159 | 160 | string absolutepath = create_absolute_path(base_path, path); 161 | 162 | virtual_file_type vft = get_file_type_from_path(absolutepath); 163 | 164 | if (vft != vft_memory_file) 165 | { 166 | asar_throw_warning(0, warning_id_check_memory_file, path, (int)warning_id_check_memory_file); 167 | } 168 | 169 | switch (vft) 170 | { 171 | case vft_physical_file: 172 | { 173 | physical_file* new_file = new physical_file; 174 | 175 | if (new_file == nullptr) 176 | { 177 | m_last_error = vfe_unknown; 178 | return INVALID_VIRTUAL_FILE_HANDLE; 179 | } 180 | 181 | virtual_file_error error = new_file->open(absolutepath); 182 | 183 | if (error != vfe_none) 184 | { 185 | delete new_file; 186 | m_last_error = error; 187 | return INVALID_VIRTUAL_FILE_HANDLE; 188 | } 189 | 190 | return static_cast(new_file); 191 | } 192 | 193 | case vft_memory_file: 194 | { 195 | if(m_memory_files.exists(absolutepath)) { 196 | memory_buffer mem_buf = m_memory_files.find(absolutepath); 197 | memory_file* new_file = new memory_file(mem_buf.data, mem_buf.length); 198 | return static_cast(new_file); 199 | } else { 200 | m_last_error = vfe_doesnt_exist; 201 | return INVALID_VIRTUAL_FILE_HANDLE; 202 | } 203 | } 204 | 205 | default: 206 | // We should not get here 207 | m_last_error = vfe_unknown; 208 | return INVALID_VIRTUAL_FILE_HANDLE; 209 | } 210 | } 211 | 212 | void virtual_filesystem::close_file(virtual_file_handle file_handle) 213 | { 214 | if (file_handle != INVALID_VIRTUAL_FILE_HANDLE) 215 | { 216 | virtual_file* file = static_cast(file_handle); 217 | 218 | file->close(); 219 | 220 | delete file; 221 | } 222 | } 223 | 224 | 225 | 226 | size_t virtual_filesystem::read_file(virtual_file_handle file_handle, void* out_buffer, size_t pos, size_t num_bytes) 227 | { 228 | if (file_handle != INVALID_VIRTUAL_FILE_HANDLE) 229 | { 230 | virtual_file* file = static_cast(file_handle); 231 | 232 | return file->read(out_buffer, pos, num_bytes); 233 | } 234 | 235 | return 0u; 236 | } 237 | 238 | size_t virtual_filesystem::get_file_size(virtual_file_handle file_handle) 239 | { 240 | if (file_handle != INVALID_VIRTUAL_FILE_HANDLE) 241 | { 242 | virtual_file* file = static_cast(file_handle); 243 | 244 | return file->get_size(); 245 | } 246 | 247 | return 0u; 248 | } 249 | 250 | 251 | virtual_filesystem::virtual_file_type virtual_filesystem::get_file_type_from_path(const char* path) 252 | { 253 | if(m_memory_files.exists(path)) { 254 | return vft_memory_file; 255 | } else { 256 | return vft_physical_file; 257 | } 258 | } 259 | 260 | void virtual_filesystem::add_memory_file(const char* name, const void* buffer, size_t length) { 261 | memory_buffer mem_buf = { buffer, length }; 262 | string normalized_path = normalize_path(name); 263 | m_memory_files.remove(normalized_path); 264 | m_memory_files.create(normalized_path) = mem_buf; 265 | 266 | } 267 | 268 | bool virtual_filesystem::is_path_absolute(const char* path) 269 | { 270 | return path_is_absolute(path); 271 | } 272 | 273 | string virtual_filesystem::create_absolute_path(const char* base, const char* target) 274 | { 275 | if (is_path_absolute(target) || base == nullptr || base[0] == '\0') 276 | { 277 | return normalize_path(target); 278 | } 279 | 280 | string path_to_use = ""; 281 | string test_path = ""; 282 | 283 | test_path = normalize_path(target); 284 | 285 | // First check if path is absolute 286 | if (path_is_absolute(test_path)) 287 | { 288 | if (m_memory_files.exists(test_path) || file_exists(test_path)) 289 | { 290 | path_to_use = test_path; 291 | } 292 | } 293 | else 294 | { 295 | // Now check if path exists relative to the base path 296 | if (base != nullptr) 297 | { 298 | test_path = create_combined_path(dir(base), target); 299 | } 300 | 301 | if (test_path != "" && (m_memory_files.exists(test_path) || file_exists(test_path))) 302 | { 303 | path_to_use = test_path; 304 | } 305 | else 306 | { 307 | // Finally check if path exists relative to any include path 308 | bool found = false; 309 | for (int i = 0; i < m_include_paths.count; ++i) 310 | { 311 | test_path = create_combined_path(m_include_paths[i], target); 312 | 313 | if (m_memory_files.exists(test_path) || file_exists(test_path)) 314 | { 315 | found = true; 316 | path_to_use = test_path; 317 | break; 318 | } 319 | } 320 | 321 | if (!found) 322 | { 323 | // Reset our path so that we don't return an empty one 324 | // (that will do some weird shit and fuck up error messages) 325 | path_to_use = target; 326 | } 327 | } 328 | } 329 | 330 | return path_to_use; 331 | } 332 | --------------------------------------------------------------------------------