--- parser3/src/classes/string.C 2015/04/21 22:12:26 1.215 +++ parser3/src/classes/string.C 2015/11/16 18:27:15 1.223 @@ -1,7 +1,7 @@ /** @file Parser: @b string parser class. - Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2015 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ @@ -20,7 +20,7 @@ #include "pa_vregex.h" #include "pa_charsets.h" -volatile const char * IDENT_STRING_C="$Id: string.C,v 1.215 2015/04/21 22:12:26 moko Exp $"; +volatile const char * IDENT_STRING_C="$Id: string.C,v 1.223 2015/11/16 18:27:15 moko Exp $"; // class @@ -53,6 +53,9 @@ DECLARE_CLASS_VAR(void, new MVoid, 0); #define MODE_APPEND "append" +#define UNESCAPE_MODE_JS "js" +#define UNESCAPE_MODE_URI "uri" + // statics static const String match_var_name(MATCH_VAR_NAME); @@ -89,25 +92,22 @@ static void _int(Request& r, MethodParam static void _double(Request& r, MethodParams& params) { const String& self_string=GET_SELF(r, VString).string(); - double converted; if(self_string.is_empty()) { if(params.count()>0) - converted=params.as_double(0, "default must be double", r); // (default) + r.write_no_lang(*new VDouble(params.as_double(0, "default must be double", r))); // (default) else throw Exception(PARSER_RUNTIME, 0, "unable to convert empty string without default specified"); } else { try { - converted=self_string.as_double(); + r.write_no_lang(*new VDouble(self_string.as_double())); } catch(...) { // convert problem if(params.count()>0) - converted=params.as_double(0, "default must be double", r); // (default) + r.write_no_lang(*new VDouble(params.as_double(0, "default must be double", r))); // (default) else rethrow; // we have a problem when no default } } - - r.write_no_lang(*new VDouble(converted)); } static void _bool(Request& r, MethodParams& params) { @@ -153,27 +153,18 @@ static void _bool(Request& r, MethodPara static void _left(Request& r, MethodParams& params) { ssize_t sn=params.as_int(0, "n must be int", r); - if(sn<0) - throw Exception(PARSER_RUNTIME, - 0, - "n(%d) must be >=0", sn); - size_t n=(size_t)sn; - const String& string=GET_SELF(r, VString).string(); - r.write_assign_lang(string.mid(r.charsets.source(), 0, n)); + r.write_assign_lang(sn<0 ? string : string.mid(r.charsets.source(), 0, (size_t)sn)); } static void _right(Request& r, MethodParams& params) { - ssize_t sn=(size_t)params.as_int(0, "n must be int", r); - if(sn<0) - throw Exception(PARSER_RUNTIME, - 0, - "n(%d) must be >=0", sn); - size_t n=(size_t)sn; - - const String& string=GET_SELF(r, VString).string(); - size_t length=string.length(r.charsets.source()); - r.write_assign_lang(n0){ + size_t n=(size_t)sn; + const String& string=GET_SELF(r, VString).string(); + size_t length=string.length(r.charsets.source()); + r.write_assign_lang(n 2) + if(HashStringValue* options=params.as_hash(2)) { + int valid_options=0; + if(Value* vcharset_name=options->get(PA_CHARSET_NAME)){ + from_charset=&::charsets.get(vcharset_name->as_string().change_case(r.charsets.source(), String::CC_UPPER)); + valid_options++; + } + if(valid_options!=options->count()) + throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION); + } + + bool mode_js; + if(mode==UNESCAPE_MODE_JS){ + mode_js=true; + } else if(mode==UNESCAPE_MODE_URI){ + mode_js=false; + } else { + throw Exception(PARSER_RUNTIME, &mode, "is invalid mode, must be either '"UNESCAPE_MODE_JS"' or '"UNESCAPE_MODE_URI"'"); + } + + const char* unescaped=unescape_chars(src.cstr(), src.length(), from_charset, mode_js); + if(*unescaped){ + const String* result=new String(Charset::transcode(unescaped, *from_charset, r.charsets.source()), String::L_TAINTED); + r.write_assign_lang(*result); + } +} + // constructor MString::MString(): Methoded("string") { @@ -844,8 +870,11 @@ MString::MString(): Methoded("string") { add_native_method("idna", Method::CT_ANY, _idna, 0, 1); // ^string.js-escape[] - add_native_method("js-escape", Method::CT_ANY, _escape, 0, 0); + add_native_method("js-escape", Method::CT_DYNAMIC, _js_escape, 0, 0); // ^string:js-unescape[escaped%uXXXXstring] - add_native_method("js-unescape", Method::CT_STATIC, _unescape, 1, 1); -} + add_native_method("js-unescape", Method::CT_STATIC, _js_unescape, 1, 1); + + // ^string:unescape[js|uri;escaped;$.charset[...]] + add_native_method("unescape", Method::CT_STATIC, _unescape, 2, 3); +}