diff --git a/lib/master.pike.in b/lib/master.pike.in index 771505bfd448e0042b87198d693d7ef374bf99e4..8383f6242650005bbeb7541229ae17df74499161 100644 --- a/lib/master.pike.in +++ b/lib/master.pike.in @@ -5686,7 +5686,7 @@ class Codec } } -// The master acts as the default codec. +// Compat. The master used to act as the default codec. inherit Codec; diff --git a/src/encode.c b/src/encode.c index 0e2ac600236b6f908623cef155bdbca6135e856e..81927e2d737d6ca5b1bc45c58465b98f889b68b0 100644 --- a/src/encode.c +++ b/src/encode.c @@ -122,6 +122,34 @@ #define ID_ENTRY_INHERIT 3 #define ID_ENTRY_ALIAS 4 +static struct object *lookup_codec (struct pike_string *codec_name) +{ + struct object *m = get_master(); + if (!m) { + /* Use a dummy if there's no master around yet. This will cause an + * error in apply later, so we don't need to bother. */ + return clone_object (null_program, 0); + } + else { + ref_push_object (m); + ref_push_string (codec_name); + o_index(); + if (UNSAFE_IS_ZERO (Pike_sp - 1)) { + add_ref (m); + return m; + } + else { + apply_svalue (Pike_sp - 1, 0); + if (Pike_sp[-1].type != T_OBJECT) + Pike_error ("master()->%s() did not return an object. Got: %O\n", + codec_name->str, Pike_sp - 1); + m = (--Pike_sp)->u.object; + pop_stack(); + return m; + } + } +} + struct encode_data { int canonic; @@ -138,6 +166,14 @@ struct encode_data #endif }; +static struct object *encoder_codec (struct encode_data *data) +{ + struct pike_string *encoder_str; + if (data->codec) return data->codec; + MAKE_CONST_STRING (encoder_str, "Encoder"); + return data->codec = lookup_codec (encoder_str); +} + /* Convert to/from forward reference ID. */ #define CONVERT_ENTRY_ID(ID) (-((ID) - COUNTER_START) - (-COUNTER_START + 1)) @@ -870,7 +906,7 @@ static void encode_value2(struct svalue *val, struct encode_data *data, int forc if (data->canonic) Pike_error("Canonical encoding of objects not supported.\n"); push_svalue(val); - apply(data->codec, "nameof", 1); + apply(encoder_codec (data), "nameof", 1); EDB(5, fprintf(stderr, "%*s->nameof: ", data->depth, ""); print_svalue(stderr, Pike_sp-1); fputc('\n', stderr);); @@ -926,7 +962,8 @@ static void encode_value2(struct svalue *val, struct encode_data *data, int forc */ data->buf.s.str[to_change] = 99; - fun = find_identifier("encode_object", data->codec->prog); + fun = find_identifier("encode_object", + encoder_codec (data)->prog); if (fun < 0) Pike_error("Cannot encode objects without an " "\"encode_object\" function in the codec.\n"); @@ -953,7 +990,7 @@ static void encode_value2(struct svalue *val, struct encode_data *data, int forc Pike_error("Canonical encoding of functions not supported.\n"); check_stack(1); push_svalue(val); - apply(data->codec,"nameof", 1); + apply(encoder_codec (data),"nameof", 1); if(Pike_sp[-1].type == T_INT && Pike_sp[-1].subtype==NUMBER_UNDEFINED) { if(val->subtype != FUNCTION_BUILTIN) @@ -1010,7 +1047,7 @@ static void encode_value2(struct svalue *val, struct encode_data *data, int forc Pike_error("Encoding of unfixated programs not supported.\n"); check_stack(1); push_svalue(val); - apply(data->codec,"nameof", 1); + apply(encoder_codec (data),"nameof", 1); if(Pike_sp[-1].type == val->type) Pike_error("Error in master()->nameof(), same type returned.\n"); if(Pike_sp[-1].type == T_INT && Pike_sp[-1].subtype == NUMBER_UNDEFINED) @@ -1840,6 +1877,7 @@ encode_done:; static void free_encode_data(struct encode_data *data) { toss_buffer(& data->buf); + if (data->codec) free_object (data->codec); free_mapping(data->encoded); free_array(data->delayed); } @@ -1856,8 +1894,10 @@ static void free_encode_data(struct encode_data *data) *! Almost any value can be coded, mappings, floats, arrays, circular *! structures etc. *! - *! If @[codec] is specified, it's used as the codec for the decode. - *! If no codec is specified, the current master object will be used. + *! If @[codec] is specified, it's used as the codec for the encode. + *! If none is specified, then one is instantiated through + *! @expr{master()->Encoder()@}. As a compatibility fallback, the + *! master itself is used if it has no @expr{Encoder@} class. *! *! If @expr{@[codec]->nameof(o)@} returns @tt{UNDEFINED@} for an *! object, @expr{val = o->encode_object(o)@} will be called. The @@ -1919,13 +1959,7 @@ void f_encode_value(INT32 args) } data->codec=Pike_sp[1-args].u.object; }else{ - data->codec=get_master(); - if (!data->codec) { - /* Use a dummy if there's no master around yet, to avoid checks. */ - push_object (clone_object (null_program, 0)); - args++; - data->codec = Pike_sp[-1].u.object; - } + data->codec=NULL; } SET_ONERROR(tmp, free_encode_data, data); @@ -1938,6 +1972,7 @@ void f_encode_value(INT32 args) UNSET_ONERROR(tmp); + if (data->codec) free_object (data->codec); free_mapping(data->encoded); free_array (data->delayed); @@ -2003,13 +2038,7 @@ void f_encode_value_canonic(INT32 args) } data->codec=Pike_sp[1-args].u.object; }else{ - data->codec=get_master(); - if (!data->codec) { - /* Use a dummy if there's no master around yet, to avoid checks. */ - push_object (clone_object (null_program, 0)); - args++; - data->codec = Pike_sp[-1].u.object; - } + data->codec=NULL; } SET_ONERROR(tmp, free_encode_data, data); @@ -2022,6 +2051,7 @@ void f_encode_value_canonic(INT32 args) UNSET_ONERROR(tmp); + if (data->codec) free_object (data->codec); free_mapping(data->encoded); free_array (data->delayed); @@ -2055,6 +2085,7 @@ struct decode_data struct unfinished_obj_link *unfinished_placeholders; struct svalue counter; struct object *codec; + int explicit_codec; int pickyness; int pass; int delay_counter; @@ -2074,6 +2105,14 @@ struct decode_data #endif }; +static struct object *decoder_codec (struct decode_data *data) +{ + struct pike_string *decoder_str; + if (data->codec) return data->codec; + MAKE_CONST_STRING (decoder_str, "Decoder"); + return data->codec = lookup_codec (decoder_str); +} + static void decode_value2(struct decode_data *data); static int my_extract_char(struct decode_data *data) @@ -2883,7 +2922,7 @@ static void decode_value2(struct decode_data *data) switch(num) { case 0: - apply(data->codec,"objectof", 1); + apply(decoder_codec (data),"objectof", 1); break; case 1: @@ -2951,11 +2990,8 @@ static void decode_value2(struct decode_data *data) ref_push_object(o); decode_value2(data); - if(!data->codec) - decode_error(data, Pike_sp - 1, - "Cannot decode object without codec.\n"); - fun = find_identifier("decode_object", data->codec->prog); + fun = find_identifier("decode_object", decoder_codec (data)->prog); if (fun < 0) decode_error(data, Pike_sp - 1, "Cannot decode objects without a " @@ -3049,7 +3085,7 @@ static void decode_value2(struct decode_data *data) switch(num) { case 0: - apply(data->codec,"functionof", 1); + apply(decoder_codec (data),"functionof", 1); break; case 1: { @@ -3126,7 +3162,7 @@ static void decode_value2(struct decode_data *data) struct program *p; decode_value2(data); - apply(data->codec,"programof", 1); + apply(decoder_codec (data),"programof", 1); p = program_from_svalue(Pike_sp-1); @@ -3181,7 +3217,7 @@ static void decode_value2(struct decode_data *data) debug_malloc_touch(p); ref_push_program(p); - apply(data->codec, "__register_new_program", 1); + apply(decoder_codec (data), "__register_new_program", 1); /* return a placeholder */ if(Pike_sp[-1].type == T_OBJECT) @@ -3694,12 +3730,8 @@ static void decode_value2(struct decode_data *data) int decode_fun = -1; struct unfinished_obj_link *l, **ptr; if (data->unfinished_objects) { - if(!data->codec) - decode_error(data, Pike_sp - 1, - "Cannot decode object without codec.\n"); - - decode_fun = - find_identifier("decode_object", data->codec->prog); + decode_fun = find_identifier("decode_object", + decoder_codec (data)->prog); if (decode_fun < 0) decode_error(data, Pike_sp - 1, "Cannot decode objects without a " @@ -3731,7 +3763,7 @@ static void decode_value2(struct decode_data *data) free((char *)l); /* Let the codec do it's job... */ - apply_low(data->codec, decode_fun, 2); + apply_low(decoder_codec (data), decode_fun, 2); if ((Pike_sp[-1].type == T_ARRAY) && ((fun = FIND_LFUN(o->prog, LFUN_CREATE)) != -1)) { /* Call lfun::create(@args). */ @@ -3814,9 +3846,8 @@ static void decode_value2(struct decode_data *data) /* Is this necessary? In that case, how do we pass an * adequate context to __register_new_program so that it * knows which program is being decoded? */ - if (data->codec) { ref_push_program (p); - apply (data->codec, "__register_new_program", 1); + apply (decoder_codec (data), "__register_new_program", 1); /* Returns a placeholder. */ if (Pike_sp[-1].type == T_OBJECT) { @@ -3829,7 +3860,6 @@ static void decode_value2(struct decode_data *data) decode_error (data, NULL, "Expected placeholder object or zero " "from __register_new_program.\n"); pop_stack(); - } #endif break; @@ -3931,7 +3961,7 @@ static void decode_value2(struct decode_data *data) { int fun = find_identifier("__register_new_program", - data->codec->prog); + decoder_codec (data)->prog); if (fun >= 0) { ref_push_program(p); @@ -4879,7 +4909,7 @@ static void free_decode_data (struct decode_data *data, int delay, #endif free_string (data->data_str); - free_object (data->codec); + if (data->codec) free_object (data->codec); free_mapping(data->decoded); while(data->unfinished_programs) @@ -4979,7 +5009,8 @@ static INT32 my_decode(struct pike_string *tmp, /* Attempt to avoid infinite recursion on circular structures. */ for (data = current_decode; data; data=data->next) { - if (data->raw == tmp && data->codec == codec + if (data->raw == tmp && + (codec ? data->codec == codec : !data->explicit_codec) #ifdef PIKE_THREADS && data->thread_state == Pike_interpreter.thread_state #endif @@ -5005,6 +5036,7 @@ static INT32 my_decode(struct pike_string *tmp, data->len=tmp->len; data->ptr=0; data->codec=codec; + data->explicit_codec = codec ? 1 : 0; data->pickyness=0; data->pass=1; data->unfinished_programs=0; @@ -5036,7 +5068,7 @@ static INT32 my_decode(struct pike_string *tmp, data->decoded=allocate_mapping(128); add_ref (data->data_str); - add_ref (data->codec); + if (data->codec) add_ref (data->codec); #ifdef PIKE_THREADS add_ref (data->thread_obj); #endif @@ -5328,7 +5360,9 @@ extern struct program *MasterCodec_program; *! coded. *! *! If @[codec] is specified, it's used as the codec for the decode. - *! If no codec is specified, the current master object will be used. + *! If none is specified, then one is instantiated through + *! @expr{master()->Decoder()@}. As a compatibility fallback, the + *! master itself is used if it has no @expr{Decoder@} class. *! *! @seealso *! @[encode_value()], @[encode_value_canonic()] @@ -5376,13 +5410,14 @@ void f_decode_value(INT32 args) } /* Fall through. */ case 1: - codec = get_master(); - if (!codec) { + if (!get_master()) { /* The codec used for decoding the master program. */ push_object (clone_object (MasterCodec_program, 0)); args++; codec = Pike_sp[-1].u.object; } + else + codec = NULL; } if(!my_decode(s, codec