From 6a01fa93c554fa2660528506cc999bec4c557810 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 27 Aug 2022 20:32:09 -0500 Subject: [PATCH] avm2: Implement `String.toLowerCase` and `String.toUpperCase` These are implemented in the same way as in AVM1. Testing in Flash Player shows that the behavior is the same. --- core/src/avm2/globals/string.rs | 42 +++++++++++++++++++ tests/tests/regression_tests.rs | 1 + tests/tests/swfs/avm2/string_case/Test.as | 23 ++++++++++ tests/tests/swfs/avm2/string_case/output.txt | 12 ++++++ tests/tests/swfs/avm2/string_case/test.fla | Bin 0 -> 3814 bytes tests/tests/swfs/avm2/string_case/test.swf | Bin 0 -> 3706 bytes 6 files changed, 78 insertions(+) create mode 100644 tests/tests/swfs/avm2/string_case/Test.as create mode 100644 tests/tests/swfs/avm2/string_case/output.txt create mode 100644 tests/tests/swfs/avm2/string_case/test.fla create mode 100644 tests/tests/swfs/avm2/string_case/test.swf diff --git a/core/src/avm2/globals/string.rs b/core/src/avm2/globals/string.rs index d0bddb788..241ce1513 100644 --- a/core/src/avm2/globals/string.rs +++ b/core/src/avm2/globals/string.rs @@ -497,6 +497,46 @@ fn substring<'gc>( Ok(Value::Undefined) } +/// Implements `String.toLowerCase` +fn to_lower_case<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, + _args: &[Value<'gc>], +) -> Result, Error> { + if let Some(this) = this { + let this_val = Value::from(this); + let this = this_val.coerce_to_string(activation)?; + return Ok(AvmString::new( + activation.context.gc_context, + this.iter() + .map(crate::string::utils::swf_to_lowercase) + .collect::(), + ) + .into()); + } + Ok(Value::Undefined) +} + +/// Implements `String.toUpperCase` +fn to_upper_case<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Option>, + _args: &[Value<'gc>], +) -> Result, Error> { + if let Some(this) = this { + let this_val = Value::from(this); + let this = this_val.coerce_to_string(activation)?; + return Ok(AvmString::new( + activation.context.gc_context, + this.iter() + .map(crate::string::utils::swf_to_uppercase) + .collect::(), + ) + .into()); + } + Ok(Value::Undefined) +} + /// Construct `String`'s class. pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { let class = Class::new( @@ -530,6 +570,8 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc> ("split", split), ("substr", substr), ("substring", substring), + ("toLowerCase", to_lower_case), + ("toUpperCase", to_upper_case), ]; write.define_as3_builtin_instance_methods(mc, AS3_INSTANCE_METHODS); diff --git a/tests/tests/regression_tests.rs b/tests/tests/regression_tests.rs index 9bbe733e5..d45b8849a 100644 --- a/tests/tests/regression_tests.rs +++ b/tests/tests/regression_tests.rs @@ -483,6 +483,7 @@ swf_tests! { (as3_stage_properties, "avm2/stage_properties", 1), (as3_stored_properties, "avm2/stored_properties", 1), (as3_strict_equality, "avm2/strict_equality", 1), + (as3_string_case, "avm2/string_case", 1), (as3_string_char_at, "avm2/string_char_at", 1), (as3_string_char_code_at, "avm2/string_char_code_at", 1), (as3_string_concat_fromcharcode, "avm2/string_concat_fromcharcode", 1), diff --git a/tests/tests/swfs/avm2/string_case/Test.as b/tests/tests/swfs/avm2/string_case/Test.as new file mode 100644 index 000000000..2288df517 --- /dev/null +++ b/tests/tests/swfs/avm2/string_case/Test.as @@ -0,0 +1,23 @@ +package { + public class Test { + public function Test() {} + } +} + +// toLowerCase +trace("// toLowerCase"); + +trace('// "teST😋".toLowerCase()'); +trace("teST😋".toLowerCase()); +trace('// All uppercase chars'); +trace("ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽƁƂƄƆƇƉƊƋƎƏƐƑƓƔƖƗƘƜƝƟƠƢƤƦƧƩƬƮƯƱƲƳƵƷƸƼDŽDžLJLjNJNjǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZDzǴǶǷǸǺǼǾȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȢȤȦȨȪȬȮȰȲΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ΢ΣΤΥΦΧΨΩΪΫϘϚϜϞϠϢϤϦϨϪϬϮϴЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯѠѢѤѦѨѪѬѮѰѲѴѶѸѺѼѾҀҊҌҎҐҒҔҖҘҚҜҞҠҢҤҦҨҪҬҮҰҲҴҶҸҺҼҾӁӃӇӋӐӒӔӖӘӚӜӞӠӢӤӦӨӪӬӮӰӲӴӶӸԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸἈἉἊἋἌἍἎἏἘἙἚἛἜἝἨἩἪἫἬἭἮἯἸἹἺἻἼἽἾἿὈὉὊὋὌὍὙὛὝὟὨὩὪὫὬὭὮὯᾈᾉᾊᾋᾌᾍᾎᾏᾘᾙᾚᾛᾜᾝᾞᾟᾨᾩᾪᾫᾬᾭᾮᾯᾸᾹᾺΆᾼῈΈῊΉῌῘῙῚΊῨῩῪΎῬῸΌῺΏῼΩKÅⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏABCDEFGHIJKLMNOPQRSTUVWXYZ".toLowerCase()); +trace(""); + +// toUpperCase +trace("// toUpperCase"); +trace('// "teST😋".toUpperCase()'); +trace("teST😋".toUpperCase()); +trace('// All lowercase chars'); +var s = "abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżžſƃƅƈƌƒƕƙơƣƥƨƭưƴƶƹƽƿDždžLjljNjnjǎǐǒǔǖǘǚǜǝǟǡǣǥǧǩǫǭǯDzdzǵǹǻǽǿȁȃȅȇȉȋȍȏȑȓȕȗșțȝȟȣȥȧȩȫȭȯȱȳɓɔɖɗəɛɠɣɨɩɯɲɵʀʃʈʊʋʒͅάέήίαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϐϑϕϖϙϛϝϟϡϣϥϧϩϫϭϯϰϱϲϵабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿҁҋҍҏґғҕҗҙқҝҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӂӄӈӌӑӓӕӗәӛӝӟӡӣӥӧөӫӭӯӱӳӵӷӹաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẛạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹἀἁἂἃἄἅἆἇἐἑἒἓἔἕἠἡἢἣἤἥἦἧἰἱἲἳἴἵἶἷὀὁὂὃὄὅὑὓὕὗὠὡὢὣὤὥὦὧὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾳιῃῐῑῠῡῥῳⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩabcdefghijklmnopqrstuvwxyz"; +trace(s.toUpperCase()); +trace(""); \ No newline at end of file diff --git a/tests/tests/swfs/avm2/string_case/output.txt b/tests/tests/swfs/avm2/string_case/output.txt new file mode 100644 index 000000000..580a60454 --- /dev/null +++ b/tests/tests/swfs/avm2/string_case/output.txt @@ -0,0 +1,12 @@ +// toLowerCase +// "teST😋".toLowerCase() +test😋 +// All uppercase chars +abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįiijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷÿźżžɓƃƅɔƈɖɗƌǝəɛƒɠɣɩɨƙɯɲɵơƣƥʀƨʃƭʈưʊʋƴƶʒƹƽdždžljljnjnjǎǐǒǔǖǘǚǜǟǡǣǥǧǩǫǭǯdzdzǵƕƿǹǻǽǿȁȃȅȇȉȋȍȏȑȓȕȗșțȝȟȣȥȧȩȫȭȯȱȳάέήίόύώαβγδεζηθικλμνξοπρςστυφχψωϊϋϙϛϝϟϡϣϥϧϩϫϭϯθѐёђѓєѕіїјљњћќѝўџабвгдежзийклмнопрстуфхцчшщъыьэюяѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿҁҋҍҏґғҕҗҙқҝҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӂӄӈӌӑӓӕӗәӛӝӟӡӣӥӧөӫӭӯӱӳӵӷӹաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆაბგდევზთიკლმნოპჟრსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹἀἁἂἃἄἅἆἇἐἑἒἓἔἕἠἡἢἣἤἥἦἧἰἱἲἳἴἵἶἷὀὁὂὃὄὅὑὓὕὗὠὡὢὣὤὥὦὧᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱὰάᾳὲέὴήῃῐῑὶίῠῡὺύῥὸόὼώῳωkåⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩabcdefghijklmnopqrstuvwxyz + +// toUpperCase +// "teST😋".toUpperCase() +TEST😋 +// All lowercase chars +ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽSƂƄƇƋƑǶƘƠƢƤƧƬƯƳƵƸƼǷDŽDŽLJLJNJNJǍǏǑǓǕǗǙǛƎǞǠǢǤǦǨǪǬǮDZDZǴǸǺǼǾȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȢȤȦȨȪȬȮȰȲƁƆƉƊƏƐƓƔƗƖƜƝƟƦƩƮƱƲƷΙΆΈΉΊΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ΢ΣΤΥΦΧΨΩΪΫΌΎΏΒΘΦΠϘϚϜϞϠϢϤϦϨϪϬϮΚΡΣΕАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏѠѢѤѦѨѪѬѮѰѲѴѶѸѺѼѾҀҊҌҎҐҒҔҖҘҚҜҞҠҢҤҦҨҪҬҮҰҲҴҶҸҺҼҾӁӃӇӋӐӒӔӖӘӚӜӞӠӢӤӦӨӪӬӮӰӲӴӶӸԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔṠẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸἈἉἊἋἌἍἎἏἘἙἚἛἜἝἨἩἪἫἬἭἮἯἸἹἺἻἼἽἾἿὈὉὊὋὌὍὙὛὝὟὨὩὪὫὬὭὮὯᾺΆῈΈῊΉῚΊῸΌῪΎῺΏᾈᾉᾊᾋᾌᾍᾎᾏᾘᾙᾚᾛᾜᾝᾞᾟᾨᾩᾪᾫᾬᾭᾮᾯᾸᾹᾼΙῌῘῙῨῩῬῼⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏABCDEFGHIJKLMNOPQRSTUVWXYZ + diff --git a/tests/tests/swfs/avm2/string_case/test.fla b/tests/tests/swfs/avm2/string_case/test.fla new file mode 100644 index 0000000000000000000000000000000000000000..c5fea5350bbdd10a755d5a3ebd85811519dc1abe GIT binary patch literal 3814 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 S#?JhOi}6WhTT$XT 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 YQ~v(R=f3{OzxCaV{6pyZFG2PLqXbb%IRF3v literal 0 HcmV?d00001