From 68ab3db594494b9c6421d0e4cfa53bc21c834c66 Mon Sep 17 00:00:00 2001 From: Rodrigo Batista de Moraes Date: Thu, 28 Nov 2024 18:40:02 -0300 Subject: [PATCH 1/3] run cargo update --- Cargo.lock | 465 ++++++++++++++++++++++++++++--------- license/about-android.toml | 9 +- license/about-linux.toml | 1 + license/about-windows.toml | 1 + 4 files changed, 370 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 40422e2..80c14cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -131,36 +131,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -274,7 +274,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] @@ -325,9 +325,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" [[package]] name = "byteorder" @@ -343,9 +343,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cairo-sys-rs" @@ -389,9 +389,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.31" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -517,9 +517,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -527,9 +527,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -546,14 +546,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] @@ -628,9 +628,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -834,7 +834,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.20", + "clap 4.5.21", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -968,6 +968,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "dlib" version = "0.5.2" @@ -999,9 +1010,9 @@ dependencies = [ [[package]] name = "dynasm" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767de053f78ef46295114c1d3bd46dff9e2542c817c9c0f313f2a6a95eaad2de" +checksum = "697c04882d6b25c9eb2583d2737bea1947a28c9d7544dddec76d85e6e1545c92" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -1009,14 +1020,14 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] name = "dynasmrt" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f814029fdd01bc8c85a5783a10932b25edae8d22f25d3152db086a6f444538d8" +checksum = "1718a074cf8317b3509228d7ea9a99d7014b17483109d701c733699065fe5e35" dependencies = [ "byteorder", "dynasm", @@ -1045,9 +1056,9 @@ dependencies = [ [[package]] name = "embed-resource" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e24052d7be71f0efb50c201557f6fe7d237cfd5a64fd5bcd7fd8fe32dbbffa" +checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379" dependencies = [ "cc", "memchr", @@ -1118,18 +1129,18 @@ dependencies = [ [[package]] name = "fdeflate" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" +checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" dependencies = [ "simd-adler32", ] [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1154,9 +1165,9 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.29.3" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719236bdbcf6033a3395165f797076b31056018e6723ccff616eb25fc9c99de1" +checksum = "d26948e37cfcb1f2c2cd38e0602d3a8ab6b9472c0c6eff4516fc8def9a3124d7" dependencies = [ "chrono", "log", @@ -1236,7 +1247,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] @@ -1338,7 +1349,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] @@ -1453,9 +1464,9 @@ dependencies = [ name = "gameroy-native" version = "0.3.1" dependencies = [ - "clap 4.5.20", - "embed-resource 2.5.0", - "flexi_logger 0.29.3", + "clap 4.5.21", + "embed-resource 2.5.1", + "flexi_logger 0.29.6", "gameroy", "gameroy-jit", "log", @@ -1716,9 +1727,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -1785,6 +1796,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1793,19 +1922,30 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "image" -version = "0.25.4" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", @@ -1836,7 +1976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", ] [[package]] @@ -1887,9 +2027,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -2000,9 +2140,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" [[package]] name = "libloading" @@ -2030,6 +2170,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -2600,9 +2746,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2695,14 +2841,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2807,9 +2953,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -2819,9 +2965,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2941,9 +3087,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -3030,29 +3176,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -3217,6 +3363,12 @@ dependencies = [ "winit 0.27.5", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stdweb" version = "0.1.3" @@ -3273,15 +3425,26 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.82" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "system-deps" version = "6.2.2" @@ -3347,22 +3510,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", ] [[package]] @@ -3434,6 +3597,16 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -3557,9 +3730,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" @@ -3567,15 +3740,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-script" version = "0.5.7" @@ -3614,9 +3778,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -3690,6 +3854,18 @@ dependencies = [ "tiny-skia-path 0.10.0", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -3772,7 +3948,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", "wasm-bindgen-shared", ] @@ -3806,7 +3982,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4429,6 +4605,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "x11-clipboard" version = "0.7.1" @@ -4479,9 +4667,9 @@ checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" [[package]] name = "xml-rs" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" +checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" [[package]] name = "xmlparser" @@ -4495,6 +4683,30 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4513,5 +4725,48 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.82", + "syn 2.0.89", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", ] diff --git a/license/about-android.toml b/license/about-android.toml index 41b94d3..ed1b991 100644 --- a/license/about-android.toml +++ b/license/about-android.toml @@ -1,5 +1,12 @@ ignore-dev-dependencies = true ignore-build-dependencies = true -accepted = ["Apache-2.0", "MIT", "Unicode-DFS-2016", "ISC", "BSD-3-Clause"] +accepted = [ + "Apache-2.0", + "MIT", + "Unicode-DFS-2016", + "Unicode-3.0", + "ISC", + "BSD-3-Clause", +] targets = ["aarch64-linux-android"] diff --git a/license/about-linux.toml b/license/about-linux.toml index e85862d..d80ba07 100644 --- a/license/about-linux.toml +++ b/license/about-linux.toml @@ -4,6 +4,7 @@ accepted = [ "Apache-2.0", "MIT", "Unicode-DFS-2016", + "Unicode-3.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", diff --git a/license/about-windows.toml b/license/about-windows.toml index 2424b62..c372409 100644 --- a/license/about-windows.toml +++ b/license/about-windows.toml @@ -4,6 +4,7 @@ accepted = [ "Apache-2.0", "MIT", "Unicode-DFS-2016", + "Unicode-3.0", "ISC", "BSD-3-Clause", "BSL-1.0", From 625334e7ab9451f3f821f3b025dd4c56706190e2 Mon Sep 17 00:00:00 2001 From: Rodrigo Batista de Moraes Date: Thu, 28 Nov 2024 18:47:57 -0300 Subject: [PATCH 2/3] core: try to read cartridge even if invalid Will now deduce the size of the rom and ram if they are invalid, and ignore things like the header checksum. In does cases `Cartridge::new` will return a `Err((erro, Some(cartridge)))`. The ui frontned is just printing the error message and using the cartridge, but ideally it would prompt the user for confirmation. --- core/src/gameboy/cartridge.rs | 163 ++++++++++++++++------- core/tests/check_interrupt_prediction.rs | 2 +- jit/tests/check_jit_compilation.rs | 2 +- libretro/src/lib.rs | 15 ++- src/rom_loading.rs | 10 +- 5 files changed, 135 insertions(+), 57 deletions(-) diff --git a/core/src/gameboy/cartridge.rs b/core/src/gameboy/cartridge.rs index 397be68..0d318cd 100644 --- a/core/src/gameboy/cartridge.rs +++ b/core/src/gameboy/cartridge.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, io::Read}; +use std::{convert::TryInto, fmt::Write, io::Read}; use crate::save_state::{LoadStateError, SaveState, SaveStateContext}; @@ -8,6 +8,31 @@ const NINTENDOO_LOGO: [u8; 48] = [ 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, ]; +// The size of the ROM in bytes, for each type of ROM size. +const ROM_SIZES: &[usize] = &[ + 2 * 0x4000, // no ROM Banking + 4 * 0x4000, + 8 * 0x4000, + 16 * 0x4000, + 32 * 0x4000, + 64 * 0x4000, + 128 * 0x4000, + 256 * 0x4000, + 512 * 0x4000, + // 72 * 0x2000, + // 80 * 0x2000, + // 96 * 0x2000, +]; + +const RAM_SIZES: &[usize] = &[ + 0, + 0x800, + 0x2000, // Single Bank + 4 * 0x2000, + 16 * 0x2000, + 8 * 0x2000, +]; + fn mbc_type_name(code: u8) -> &'static str { match code { 0x00 => "ROM ONLY", @@ -114,27 +139,9 @@ impl CartridgeHeader { self.logo[..0x18] == NINTENDOO_LOGO[..0x18] } - pub fn rom_size_in_bytes(&self) -> Result { - let rom_sizes = [ - 2 * 0x4000, // no ROM Banking - 4 * 0x4000, - 8 * 0x4000, - 16 * 0x4000, - 32 * 0x4000, - 64 * 0x4000, - 128 * 0x4000, - 256 * 0x4000, - 512 * 0x4000, - // 72 * 0x2000, - // 80 * 0x2000, - // 96 * 0x2000, - ]; + pub fn rom_size_in_bytes(&self) -> Option { let rom_size_type = self.rom_size; - let rom_size = rom_sizes - .get(rom_size_type as usize) - .copied() - .ok_or_else(|| format!("Rom size '{:02x}' is no supported", rom_size_type))?; - Ok(rom_size) + ROM_SIZES.get(rom_size_type as usize).copied() } pub fn title_as_string(&self) -> String { @@ -170,6 +177,21 @@ pub struct Cartridge { pub ram: Vec, mbc: Mbc, } + +impl std::fmt::Debug for Cartridge { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Cartridge") + // .field("header", &self.header) + .field("lower_bank", &self.lower_bank) + .field("upper_bank", &self.upper_bank) + .field("rom.len()", &self.rom.len()) + .field("ram.len()", &self.ram.len()) + // .field("mbc", &self.mbc) + .field("kind_name", &self.kind_name()) + .finish() + } +} + impl SaveState for Cartridge { fn save_state( &self, @@ -208,21 +230,49 @@ impl SaveState for Cartridge { } } impl Cartridge { - pub fn new(rom: Vec) -> Result { + /// Create a new cartridge from the given ROM. If the ROM is invalid, return the a error + /// message and a deduced cartridge, if possible. + #[allow(clippy::result_large_err)] + pub fn new(mut rom: Vec) -> Result)> { + let mut error = String::new(); + let header = match CartridgeHeader::from_bytes(&rom) { - Ok(x) | Err((Some(x), _)) => x, - Err((None, err)) => return Err(err), + Ok(x) => x, + Err((Some(x), err)) => { + writeln!(&mut error, "{}", err).unwrap(); + x + } + Err((None, err)) => return Err((err, None)), }; - let rom_size = header.rom_size_in_bytes()?; - - if rom_size != rom.len() { - return Err(format!( - "In the rom header the expected size is '{}' bytes, but the given rom has '{}' bytes", - rom_size, - rom.len() - )); - } + let rom_size = header + .rom_size_in_bytes() + .ok_or_else(|| format!("Rom size type '{:02x}' is not supported", header.rom_size)); + + match rom_size { + Ok(rom_size) if rom_size != rom.len() => { + let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); + writeln!( + &mut error, + "The ROM header expected rom size as '{}' bytes, but the given rom has '{}' bytes. Deducing size from ROM size as {}.", + rom_size, + rom.len(), + size, + ).unwrap(); + rom.resize(size, 0); + } + Ok(_) => {} + Err(err) => { + let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); + writeln!( + &mut error, + "{}, deducing size from ROM size as {}", + err, size, + ) + .unwrap(); + rom.resize(size, 0); + } + }; // Cartridge Type let mbc_kind = header.cartridge_type; @@ -252,44 +302,57 @@ impl Cartridge { 0x0F..=0x13 => Mbc::Mbc3(Mbc3::new()), 0x19..=0x1E => Mbc::Mbc5(Mbc5::new()), _ => { - return Err(format!( + writeln!( + &mut error, "MBC type '{}' ({:02x}) is not supported", mbc_type_name(mbc_kind), mbc_kind - )) + ) + .unwrap(); + return Err((error, None)); } }; - let ram_sizes = [ - 0, - 0x800, - 0x2000, // Single Bank - 4 * 0x2000, - 16 * 0x2000, - 8 * 0x2000, - ]; let ram_size_type = header.ram_size; let ram_size = if let Mbc::Mbc2(_) = mbc { if ram_size_type != 0 { - return Err(format!("Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'", ram_size_type)); + writeln!( + &mut error, + "Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'", + ram_size_type, + ).unwrap(); } 0x200 } else { - ram_sizes - .get(ram_size_type as usize) - .copied() - .ok_or_else(|| format!("Ram size '{:02x}' is no supported", ram_size_type))? + match RAM_SIZES.get(ram_size_type as usize).copied() { + Some(x) => x, + None => { + writeln!( + &mut error, + "Ram size type '{:02x}' is not supported, using RAM size as 0x2000", + ram_size_type, + ) + .unwrap(); + 0x2000 + } + } }; - Ok(Self { + let cartridge = Self { header, lower_bank: 0, upper_bank: 1, rom, ram: vec![0; ram_size], mbc, - }) + }; + + if !error.is_empty() { + return Err((error, Some(cartridge))); + } + + Ok(cartridge) } /// A Cartridge filled with HALT instructions. Used as a test cartridge, when the CPU does not diff --git a/core/tests/check_interrupt_prediction.rs b/core/tests/check_interrupt_prediction.rs index 5d10ba2..ec002f8 100644 --- a/core/tests/check_interrupt_prediction.rs +++ b/core/tests/check_interrupt_prediction.rs @@ -100,7 +100,7 @@ fn test_interrupt_prediction(rom: &str, timeout: u64) -> bool { let rom = std::fs::read(rom_path).unwrap(); let cartridge = match Cartridge::new(rom) { Ok(x) => x, - Err(x) => { + Err((x, _)) => { eprintln!("Error reading rom: {}", x); return true; } diff --git a/jit/tests/check_jit_compilation.rs b/jit/tests/check_jit_compilation.rs index 87ef54e..c06c405 100644 --- a/jit/tests/check_jit_compilation.rs +++ b/jit/tests/check_jit_compilation.rs @@ -162,7 +162,7 @@ fn test_interrupt_prediction(rom: &str, timeout: u64) -> bool { }; let cartridge = match Cartridge::new(rom) { Ok(x) => x, - Err(x) => { + Err((x, _)) => { eprintln!("Error reading rom: {}", x); return true; } diff --git a/libretro/src/lib.rs b/libretro/src/lib.rs index 487fd7b..1b50498 100644 --- a/libretro/src/lib.rs +++ b/libretro/src/lib.rs @@ -174,12 +174,16 @@ extern "C" fn retro_load_game(info: Option<&retro_game_info>) -> bool { log::info!("retro load game"); // load rom data into core - let Some(info) = info else { return false } ; + let Some(info) = info else { return false }; let data = unsafe { std::slice::from_raw_parts(info.data as *const u8, info.size as usize) }; let cartridge = match Cartridge::new(data.to_vec()) { - Ok(x) => x, - Err(err) => { + Ok(rom) => rom, + Err((err, Some(rom))) => { + log::warn!("Warnings when loading rom: {}", err); + rom + } + Err((err, None)) => { log::error!("Error loading rom: {}", err); return false; } @@ -371,7 +375,10 @@ impl log::Log for RetroLogger { let Ok(mut file) = std::fs::OpenOptions::new() .create(true) .append(true) - .open(path) else { return }; + .open(path) + else { + return; + }; let _ = writeln!( &mut file, diff --git a/src/rom_loading.rs b/src/rom_loading.rs index 3a962bc..e3f40f3 100644 --- a/src/rom_loading.rs +++ b/src/rom_loading.rs @@ -22,7 +22,15 @@ cfg_if::cfg_if! { pub fn load_gameboy(rom: Vec, ram: Option>) -> Result, String> { let boot_rom = load_boot_rom(); - let mut cartridge = Cartridge::new(rom)?; + let mut cartridge = match Cartridge::new(rom) { + Ok(rom) => Ok(rom), + Err((warn, Some(rom))) => { + println!("Warning: {}", warn); + log::error!("{}", warn); + Ok(rom) + } + Err((err, None)) => Err(err), + }?; log::info!("Cartridge type: {}", cartridge.kind_name()); if let Some(ram) = ram { From 5bda6a1c4064e146bc14ba9bcbbe43baf617066c Mon Sep 17 00:00:00 2001 From: Rodrigo Batista de Moraes Date: Thu, 28 Nov 2024 22:03:04 -0300 Subject: [PATCH 3/3] core: add cli option for overriding mbc type You can know pass, for example, `--mbc='MBC1,0x8000,0x2000'` to the cli to override the mbc type, rom size and ram size. --- core/src/gameboy/cartridge.rs | 299 +++++++++++++++++++++++----------- core/src/parser/mod.rs | 4 + core/src/parser/size.rs | 114 +++++++++++++ native/src/main.rs | 19 ++- src/rom_loading.rs | 14 +- 5 files changed, 352 insertions(+), 98 deletions(-) create mode 100644 core/src/parser/size.rs diff --git a/core/src/gameboy/cartridge.rs b/core/src/gameboy/cartridge.rs index 0d318cd..e553d2b 100644 --- a/core/src/gameboy/cartridge.rs +++ b/core/src/gameboy/cartridge.rs @@ -166,6 +166,174 @@ enum Mbc { Mbc5(Mbc5), } +enum MbcKind { + Mbc0, + Mbc1, + Mbc1M, + Mbc2, + Mbc3, + Mbc5, +} + +pub struct MbcSpecification { + // The mbc type, as indicated in the cartridge header. + kind: MbcKind, + // The rom size, in bytes. Should be a value in ROM_SIZES. + rom_size: usize, + // The ram size, in bytes. Should be a value in RAM_SIZES. + ram_size: usize, +} + +impl MbcSpecification { + fn from_str(string: &str) -> Result { + let mut parts = string.split(','); + + let error_message = "expected 3 comma separated values"; + + let kind = parts.next().ok_or(error_message)?; + let rom_size = parts.next().ok_or(error_message)?; + let ram_size = parts.next().ok_or(error_message)?; + + if parts.next().is_some() { + return Err(error_message.to_string()); + } + + let kind = match kind { + "MBC1" => MbcKind::Mbc1, + "MBC1M" => MbcKind::Mbc1M, + "MBC2" => MbcKind::Mbc2, + "MBC3" => MbcKind::Mbc3, + "MBC5" => MbcKind::Mbc5, + _ => return Err(format!("invalid mbc type '{}'", kind)), + }; + + let rom_size = crate::parser::parse_size(rom_size) + .ok() + .or_else(|| crate::parser::parse_number(rom_size).ok()) + .ok_or_else(|| format!("invalid rom size '{}'", rom_size))? + as usize; + + ROM_SIZES + .iter() + .find(|&&x| x == rom_size) + .ok_or_else(|| format!("invalid rom size '{}'", rom_size))?; + + let ram_size = crate::parser::parse_size(ram_size) + .ok() + .or_else(|| crate::parser::parse_number(ram_size).ok()) + .ok_or_else(|| format!("invalid ram size '{}'", ram_size))? + as usize; + + RAM_SIZES + .iter() + .find(|&&x| x == ram_size) + .ok_or_else(|| format!("invalid ram size '{}'", ram_size))?; + + Ok(Self { + kind, + rom_size, + ram_size, + }) + } + + fn from_header(header: &CartridgeHeader, error: &mut String, rom: &[u8]) -> Option { + let rom_size = header + .rom_size_in_bytes() + .ok_or_else(|| format!("Rom size type '{:02x}' is not supported", header.rom_size)); + + let rom_size = match rom_size { + Ok(rom_size) if rom_size != rom.len() => { + let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); + writeln!( + error, + "The ROM header expected rom size as '{}' bytes, but the given rom has '{}' bytes. Deducing size from ROM size as {}.", + rom_size, + rom.len(), + size, + ).unwrap(); + size + } + Ok(size) => size, + Err(err) => { + let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); + writeln!(error, "{}, deducing size from ROM size as {}", err, size,).unwrap(); + size + } + }; + + // Cartridge Type + let mbc_kind = header.cartridge_type; + let kind = match mbc_kind { + 0 | 8 | 9 => MbcKind::Mbc0, + 1..=3 => 'mbc1: { + // Detect if it is a MBC1M card + if header.rom_size == 5 { + let mut number_of_games = 0; + for i in 0..4 { + let header = match CartridgeHeader::from_bytes(&rom[i * 0x40000..]) { + Ok(x) | Err((Some(x), _)) => x, + Err((None, _)) => continue, + }; + if header.check_logo() { + number_of_games += 1; + } + } + // multicarts will have, at least, a game selecion screen, and two other games. + if number_of_games >= 3 { + break 'mbc1 MbcKind::Mbc1M; + } + } + MbcKind::Mbc1 + } + 5 | 6 => MbcKind::Mbc2, + 0x0F..=0x13 => MbcKind::Mbc3, + 0x19..=0x1E => MbcKind::Mbc5, + _ => { + writeln!( + error, + "MBC type '{}' ({:02x}) is not supported", + mbc_type_name(mbc_kind), + mbc_kind + ) + .unwrap(); + return None; + } + }; + + let ram_size_type = header.ram_size; + + let ram_size = if let MbcKind::Mbc2 = kind { + if ram_size_type != 0 { + writeln!( + error, + "Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'", + ram_size_type, + ).unwrap(); + } + 0x200 + } else { + match RAM_SIZES.get(ram_size_type as usize).copied() { + Some(x) => x, + None => { + writeln!( + error, + "Ram size type '{:02x}' is not supported, using RAM size as 0x2000", + ram_size_type, + ) + .unwrap(); + 0x2000 + } + } + }; + + Some(Self { + kind, + rom_size, + ram_size, + }) + } +} + #[derive(PartialEq, Eq, Clone)] pub struct Cartridge { pub header: CartridgeHeader, @@ -229,11 +397,32 @@ impl SaveState for Cartridge { Ok(()) } } + +#[allow(clippy::result_large_err)] impl Cartridge { + pub fn new(rom: Vec) -> Result)> { + Self::new_maybe_with_spec(rom, None) + } + + pub fn new_with_spec_str( + rom: Vec, + spec: Option<&str>, + ) -> Result)> { + Self::new_maybe_with_spec( + rom, + match spec { + None => None, + Some(spec) => Some(MbcSpecification::from_str(spec).map_err(|x| (x, None))?), + }, + ) + } + /// Create a new cartridge from the given ROM. If the ROM is invalid, return the a error /// message and a deduced cartridge, if possible. - #[allow(clippy::result_large_err)] - pub fn new(mut rom: Vec) -> Result)> { + fn new_maybe_with_spec( + mut rom: Vec, + spec: Option, + ) -> Result)> { let mut error = String::new(); let header = match CartridgeHeader::from_bytes(&rom) { @@ -245,98 +434,26 @@ impl Cartridge { Err((None, err)) => return Err((err, None)), }; - let rom_size = header - .rom_size_in_bytes() - .ok_or_else(|| format!("Rom size type '{:02x}' is not supported", header.rom_size)); - - match rom_size { - Ok(rom_size) if rom_size != rom.len() => { - let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); - writeln!( - &mut error, - "The ROM header expected rom size as '{}' bytes, but the given rom has '{}' bytes. Deducing size from ROM size as {}.", - rom_size, - rom.len(), - size, - ).unwrap(); - rom.resize(size, 0); - } - Ok(_) => {} - Err(err) => { - let size = *ROM_SIZES.iter().find(|&&x| x >= rom.len()).unwrap(); - writeln!( - &mut error, - "{}, deducing size from ROM size as {}", - err, size, - ) - .unwrap(); - rom.resize(size, 0); - } + let spec = match spec { + Some(spec) => spec, + None => match MbcSpecification::from_header(&header, &mut error, &rom) { + Some(v) => v, + None => return Err((error, None)), + }, }; - // Cartridge Type - let mbc_kind = header.cartridge_type; - let mbc = match mbc_kind { - 0 | 8 | 9 => Mbc::None(Mbc0 {}), - 1..=3 => 'mbc1: { - // Detect if it is a MBC1M card - if header.rom_size == 5 { - let mut number_of_games = 0; - for i in 0..4 { - let header = match CartridgeHeader::from_bytes(&rom[i * 0x40000..]) { - Ok(x) | Err((Some(x), _)) => x, - Err((None, _)) => continue, - }; - if header.check_logo() { - number_of_games += 1; - } - } - // multicarts will have, at least, a game selecion screen, and two other games. - if number_of_games >= 3 { - break 'mbc1 Mbc::Mbc1M(Mbc1M::new()); - } - } - Mbc::Mbc1(Mbc1::new()) - } - 5 | 6 => Mbc::Mbc2(Mbc2::new()), - 0x0F..=0x13 => Mbc::Mbc3(Mbc3::new()), - 0x19..=0x1E => Mbc::Mbc5(Mbc5::new()), - _ => { - writeln!( - &mut error, - "MBC type '{}' ({:02x}) is not supported", - mbc_type_name(mbc_kind), - mbc_kind - ) - .unwrap(); - return Err((error, None)); - } - }; + let rom_size = spec.rom_size; - let ram_size_type = header.ram_size; + // resize the rom in case the header expected a different size + rom.resize(rom_size, 0); - let ram_size = if let Mbc::Mbc2(_) = mbc { - if ram_size_type != 0 { - writeln!( - &mut error, - "Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'", - ram_size_type, - ).unwrap(); - } - 0x200 - } else { - match RAM_SIZES.get(ram_size_type as usize).copied() { - Some(x) => x, - None => { - writeln!( - &mut error, - "Ram size type '{:02x}' is not supported, using RAM size as 0x2000", - ram_size_type, - ) - .unwrap(); - 0x2000 - } - } + let mbc = match spec.kind { + MbcKind::Mbc0 => Mbc::None(Mbc0 {}), + MbcKind::Mbc1 => Mbc::Mbc1(Mbc1::new()), + MbcKind::Mbc1M => Mbc::Mbc1M(Mbc1M::new()), + MbcKind::Mbc2 => Mbc::Mbc2(Mbc2::new()), + MbcKind::Mbc3 => Mbc::Mbc3(Mbc3::new()), + MbcKind::Mbc5 => Mbc::Mbc5(Mbc5::new()), }; let cartridge = Self { @@ -344,7 +461,7 @@ impl Cartridge { lower_bank: 0, upper_bank: 1, rom, - ram: vec![0; ram_size], + ram: vec![0; spec.ram_size], mbc, }; diff --git a/core/src/parser/mod.rs b/core/src/parser/mod.rs index 97eff52..8043184 100644 --- a/core/src/parser/mod.rs +++ b/core/src/parser/mod.rs @@ -1,5 +1,9 @@ use std::io::{Read, Seek, SeekFrom}; +mod size; + +pub use size::{parse_number, parse_size}; + fn read_u32(file: &mut impl Read) -> Result { let mut value = [0; 4]; file.read_exact(&mut value)?; diff --git a/core/src/parser/size.rs b/core/src/parser/size.rs new file mode 100644 index 0000000..392dcd4 --- /dev/null +++ b/core/src/parser/size.rs @@ -0,0 +1,114 @@ +use std::num::ParseIntError; + +#[derive(Debug, PartialEq)] +pub enum ParseSizeError { + InvalidFormat, + InvalidSuffix, + NumberTooLarge, + ParseError(ParseIntError), +} + +pub fn parse_number(input: &str) -> Result { + if let Some(stripped) = input.strip_prefix("0x") { + u64::from_str_radix(stripped, 16) + } else { + input.parse() + } +} + +pub fn parse_size(input: &str) -> Result { + if input.is_empty() { + return Err(ParseSizeError::InvalidFormat); + } + + let (num_part, suffix) = input.trim().split_at( + input + .find(|c: char| !c.is_ascii_digit() && c != 'x') + .unwrap_or(input.len()), + ); + + let num = parse_number(num_part).map_err(ParseSizeError::ParseError)?; + + let multiplier = match suffix.trim() { + "B" => 1, + "kB" => 1_024, + "MB" => 1_024 * 1_024, + "GB" => 1_024 * 1_024 * 1_024, + "" => return Err(ParseSizeError::InvalidFormat), + _ => return Err(ParseSizeError::InvalidSuffix), + }; + + let result = num + .checked_mul(multiplier as u64) + .ok_or(ParseSizeError::NumberTooLarge)?; + + if result > u32::MAX as u64 { + return Err(ParseSizeError::NumberTooLarge); + } + + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_number_decimal() { + assert_eq!(parse_number("123"), Ok(123)); + assert_eq!(parse_number("0"), Ok(0)); + } + + #[test] + fn test_parse_number_hexadecimal() { + assert_eq!(parse_number("0x10"), Ok(16)); + assert_eq!(parse_number("0x1F4"), Ok(500)); + } + + #[test] + fn test_parse_number_invalid() { + assert!(parse_number("not_a_number").is_err()); + assert!(parse_number("0xZZZ").is_err()); + } + + #[test] + fn test_parse_size_with_hexadecimal() { + assert_eq!(parse_size("0x100B"), Ok(256)); + assert_eq!(parse_size("0x1kB"), Ok(1_024)); + assert_eq!(parse_size("0x2MB"), Ok(2 * 1_024 * 1_024)); + } + + #[test] + fn test_valid_sizes() { + assert_eq!(parse_size("0B"), Ok(0)); + assert_eq!(parse_size("256B"), Ok(256)); + assert_eq!(parse_size("1kB"), Ok(1_024)); + assert_eq!(parse_size("2MB"), Ok(2 * 1_024 * 1_024)); + assert_eq!(parse_size("1GB"), Ok(1_024 * 1_024 * 1_024)); + } + + #[test] + fn test_invalid_formats() { + assert_eq!(parse_size(""), Err(ParseSizeError::InvalidFormat)); + assert_eq!(parse_size("256"), Err(ParseSizeError::InvalidFormat)); + assert_eq!(parse_size("256MBExtra"), Err(ParseSizeError::InvalidSuffix)); + } + + #[test] + fn test_invalid_suffix() { + assert_eq!(parse_size("256mB"), Err(ParseSizeError::InvalidSuffix)); + assert_eq!(parse_size("256TB"), Err(ParseSizeError::InvalidSuffix)); + } + + #[test] + fn test_parse_errors() { + assert!(matches!( + parse_size("not_a_numberMB"), + Err(ParseSizeError::ParseError(_)) + )); + assert!(matches!( + parse_size("0xnot_hexB"), + Err(ParseSizeError::ParseError(_)) + )); + } +} diff --git a/native/src/main.rs b/native/src/main.rs index 5d77978..268b30b 100644 --- a/native/src/main.rs +++ b/native/src/main.rs @@ -11,7 +11,7 @@ use std::path::PathBuf; use clap::{ArgAction, Args, Parser, Subcommand}; use gameroy_lib::config::parse_screen_size; -use gameroy_lib::{config, gameroy, rom_loading::load_gameboy, RomFile}; +use gameroy_lib::{config, gameroy, rom_loading::load_gameboy_with_spec, RomFile}; mod bench; @@ -35,7 +35,7 @@ pub struct Cli { // // The disassembly produced follows no particular synxtax, and don't show all instructions or // data. It only shows instructions that are statically reachable from the entry point. - #[arg(long)] + #[arg(long, requires("rom_path"))] disassembly: bool, /// Play the given .vbm file @@ -74,6 +74,17 @@ pub struct Cli { #[arg(long, value_name = "WIDTHxHEIGHT")] screen_size: Option, + /// The MBC type of the rom + /// + /// Overrides the MBC type of the rom, useful in case its is not correctly detected. Must be a + /// string in the format ",,", where is the MBC type (either + /// "MBC1", "MBC1M", "MBC2", "MBC3" or "MBC5"), is the size of the rom in bytes, and + /// is the size of the ram in bytes. The sizes must be a power of 2 multiple of + /// 0x4000. The size can be in decimal or hexadecimal format, and can have a suffix of "B", + /// + #[arg(long)] + mbc: Option, + #[command(subcommand)] command: Option, } @@ -202,7 +213,7 @@ pub fn main() { Err(e) => return eprintln!("failed to load '{}': {}", rom_path, e), }; - let gb = load_gameboy(rom, None); + let gb = load_gameboy_with_spec(rom, None, args.mbc.as_deref()); let mut gb = match gb { Ok(x) => x, Err(e) => return eprintln!("failed to load rom: {}", e), @@ -230,7 +241,7 @@ pub fn main() { let file = RomFile::from_path(PathBuf::from(rom_path)); - let gb = load_gameboy(rom, None); + let gb = load_gameboy_with_spec(rom, None, args.mbc.as_deref()); match gb { Ok(x) => Some((file, x)), Err(e) => return eprintln!("failed to load rom: {}", e), diff --git a/src/rom_loading.rs b/src/rom_loading.rs index e3f40f3..498037d 100644 --- a/src/rom_loading.rs +++ b/src/rom_loading.rs @@ -20,13 +20,21 @@ cfg_if::cfg_if! { } pub fn load_gameboy(rom: Vec, ram: Option>) -> Result, String> { + load_gameboy_with_spec(rom, ram, None) +} + +pub fn load_gameboy_with_spec( + rom: Vec, + ram: Option>, + spec: Option<&str>, +) -> Result, String> { let boot_rom = load_boot_rom(); - let mut cartridge = match Cartridge::new(rom) { + let mut cartridge = match Cartridge::new_with_spec_str(rom, spec) { Ok(rom) => Ok(rom), Err((warn, Some(rom))) => { - println!("Warning: {}", warn); - log::error!("{}", warn); + println!("Warning: {}", warn.strip_suffix('\n').unwrap_or(&warn)); + log::warn!("{}", warn); Ok(rom) } Err((err, None)) => Err(err),