pike.git / src / encode.c

version» Context lines:

pike.git/src/encode.c:115:   #define ID_ENTRY_TYPE_CONSTANT -4   #define ID_ENTRY_EFUN_CONSTANT -3   #define ID_ENTRY_RAW -2   #define ID_ENTRY_EOT -1   #define ID_ENTRY_VARIABLE 0   #define ID_ENTRY_FUNCTION 1   #define ID_ENTRY_CONSTANT 2   #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;    struct object *codec;    struct svalue counter;    struct mapping *encoded;    /* The encoded mapping maps encoded things to their entry IDs. A    * value less than COUNTER_START means that it's a forward reference    * to a thing not yet encoded. */    struct array *delayed;    dynamic_buffer buf;   #ifdef ENCODE_DEBUG    int debug, depth;   #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))      static void encode_value2(struct svalue *val, struct encode_data *data, int force_encode);      #define addstr(s, l) low_my_binary_strcat((s), (l), &(data->buf))   #define addchar(t) low_my_putchar((char)(t), &(data->buf))      /* Code a pike string */   
pike.git/src/encode.c:863: Inside #if defined(AUTO_BIGNUM)
   Pike_error("Gmp.mpz->digits did not return a string!\n");    encode_value2(Pike_sp-1, data, 0);    pop_stack();    break;    }   #endif       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););    switch(Pike_sp[-1].type)    {    case T_INT:    if(Pike_sp[-1].subtype == NUMBER_UNDEFINED)    {    int to_change = data->buf.s.len;    struct svalue tmp = entry_id;
pike.git/src/encode.c:919:    int fun;    EDB(1,fprintf(stderr, "%*sZapping 3 -> 1 in TAG_OBJECT\n",    data->depth, ""));       /* This causes the code_entry above to    * become: code_entry(TAG_OBJECT, 1, data);    * -Hubbe    */    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");    apply_low(data->codec,fun,1);       /* Put value back in cache for future reference -Hubbe */    mapping_insert(data->encoded, val, &tmp);    }    break;    }
pike.git/src/encode.c:946:    encode_value2(Pike_sp-1, data, 0);    pop_stack();    break;       case T_FUNCTION:    /* FIXME: Ought to have special treatment of trampolines. */    if (data->canonic)    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)    {    if(really_low_find_shared_string_identifier(    ID_FROM_INT(val->u.object->prog, val->subtype)->name,    val->u.object->prog,    SEE_PROTECTED|SEE_PRIVATE)==val->subtype)    {    /* We have to remove ourself from the cache for now */
pike.git/src/encode.c:1003:    encode_value2(Pike_sp-1, data, 0);    pop_stack();    break;    }    if (data->canonic)    Pike_error("Canonical encoding of programs not supported.\n");    if (!(val->u.program->flags & PROGRAM_FIXED))    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)    {    struct program *p=val->u.program;    debug_malloc_touch(p);    pop_stack();    if( (p->flags & PROGRAM_HAS_C_METHODS) || p->event_handler )    {    if(p->parent)
pike.git/src/encode.c:1833:   encode_done:;      #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif   }      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);   }      /*! @decl string encode_value(mixed value, Codec|void codec)    *!    *! Code a value into a string.    *!    *! This function takes a value, and converts it to a string. This string    *! can then be saved, sent to another Pike process, packed or used in    *! any way you like. When you want your value back you simply send this    *! string to @[decode_value()] and it will return the value you encoded.    *!    *! 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    *! returned value will be passed to @expr{o->decode_object(o, val)@}    *! when the object is decoded.    *!    *! @note    *!    *! When only simple types like int, floats, strings, mappings,    *! multisets and arrays are encoded, the produced string is very
pike.git/src/encode.c:1912:   #endif       if(args > 1 && Pike_sp[1-args].type == T_OBJECT)    {    if (Pike_sp[1-args].subtype) {    Pike_error("encode_value: "    "The codec may not be a subtyped object yet.\n");    }    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);    addstr("\266ke0", 4);       encode_value2(Pike_sp-args, data, 1);       for (i = 0; i < data->delayed->size; i++)    encode_value2 (ITEM(data->delayed) + i, data, 2);       UNSET_ONERROR(tmp);    -  +  if (data->codec) free_object (data->codec);    free_mapping(data->encoded);    free_array (data->delayed);       pop_n_elems(args);    push_string(low_free_buf(&data->buf));   }      /*! @decl string encode_value_canonic(mixed value, object|void codec)    *!    *! Code a value into a string on canonical form.
pike.git/src/encode.c:1996:   #endif       if(args > 1 && Pike_sp[1-args].type == T_OBJECT)    {    if (Pike_sp[1-args].subtype) {    Pike_error("encode_value_canonic: "    "The codec may not be a subtyped object yet.\n");    }    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);    addstr("\266ke0", 4);       encode_value2(Pike_sp-args, data, 1);       for (i = 0; i < data->delayed->size; i++)    encode_value2 (ITEM(data->delayed) + i, data, 2);       UNSET_ONERROR(tmp);    -  +  if (data->codec) free_object (data->codec);    free_mapping(data->encoded);    free_array (data->delayed);       pop_n_elems(args);    push_string(low_free_buf(&data->buf));   }         struct unfinished_prog_link   {
pike.git/src/encode.c:2048:    struct pike_string *data_str;    unsigned char *data;    ptrdiff_t len;    ptrdiff_t ptr;    struct mapping *decoded;    struct unfinished_prog_link *unfinished_programs;    struct unfinished_obj_link *unfinished_objects;    struct unfinished_obj_link *unfinished_placeholders;    struct svalue counter;    struct object *codec; +  int explicit_codec;    int pickyness;    int pass;    int delay_counter;    struct pike_string *raw;    struct decode_data *next;   #ifdef PIKE_THREADS    struct thread_state *thread_state;    struct object *thread_obj;   #endif   #ifdef ENCODE_DEBUG    int debug, depth;   #endif   #if TWO_PASS_DECODE_WORKS    /* The delay stuff can trig a second pass through the decoder,    * but it doesn't seem to really handle that. /mast */    struct Supporter supporter;   #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)   {    if(data->ptr >= data->len)    Pike_error("Decode error: Not enough data in string.\n");    return data->data [ data->ptr++ ];   }      static DECLSPEC(noreturn) void decode_error (
pike.git/src/encode.c:2876:    {    int subtype = 0;    if (num == 4) {    decode_number(subtype, data);    }    decode_value2(data);       switch(num)    {    case 0: -  apply(data->codec,"objectof", 1); +  apply(decoder_codec (data),"objectof", 1);    break;       case 1:    {    int fun;    /* decode_value_clone_object does not call __INIT, so    * we want to do that ourselves...    */    struct object *o=decode_value_clone_object(Pike_sp-1);   
pike.git/src/encode.c:2944:    }    }       EDB(2,fprintf(stderr, "%*sDecoded an object to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr););       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 "    "\"decode_object\" function in the codec.\n");    apply_low(data->codec,fun,2);    if ((Pike_sp[-1].type == T_ARRAY) && o->prog &&    ((fun = FIND_LFUN(o->prog, LFUN_CREATE)) != -1)) {    /* Call lfun::create(@args). */    INT32 args;    Pike_sp--;
pike.git/src/encode.c:3042:    break;    }       case TAG_FUNCTION:    decode_value2(data);    stack_dup(); /* For diagnostic purposes... */       switch(num)    {    case 0: -  apply(data->codec,"functionof", 1); +  apply(decoder_codec (data),"functionof", 1);    break;       case 1: {    struct program *p;    if(Pike_sp[-1].type != T_OBJECT && data->pickyness)    decode_error(data, NULL,    "Failed to decode function object. Got: %O\n",    Pike_sp - 1);       decode_value2(data);
pike.git/src/encode.c:3119:    EDB(3,    fprintf(stderr, "%*s TAG_PROGRAM(%d)\n",    data->depth, "", num));    switch(num)    {    case 0:    {    struct program *p;       decode_value2(data); -  apply(data->codec,"programof", 1); +  apply(decoder_codec (data),"programof", 1);       p = program_from_svalue(Pike_sp-1);       if (!p) {    if(data->pickyness)    decode_error(data, NULL, "Failed to decode program. Got: %O\n",    Pike_sp - 1);    pop_stack();    push_undefined();    break;
pike.git/src/encode.c:3174:       if(data->pass == 1)    {   #if TWO_PASS_DECODE_WORKS    if(! data->supporter.prog)    data->supporter.prog = p;   #endif       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)    {    placeholder=Pike_sp[-1].u.object;    if(placeholder->prog != null_program)    decode_error(data, NULL, "Placeholder object is not "    "a __null_program clone.\n");    dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;
pike.git/src/encode.c:3687:    }    }       /* Go through the linked list of unfinished objects    * to see what objects are now finished.    */    {    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 "    "\"decode_object\" function in the codec.\n");    }    for(ptr= &data->unfinished_objects ; (l=*ptr);)    {    int fun;    struct object *o=l->o;    if(o->prog)
pike.git/src/encode.c:3724:    }       /* Note: We steal the references from l. */    push_object(o);    *(Pike_sp++) = l->decode_arg;       *ptr = l->next;    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). */    INT32 args;    Pike_sp--;    args = Pike_sp->u.array->size;    if (args) {    /* Note: Eats reference to the array. */    push_array_items(Pike_sp->u.array);    } else {
pike.git/src/encode.c:3807:    data->depth, "", entry_id.u.integer);    print_svalue (stderr, Pike_sp - 1);    fputc ('\n', stderr););       data->delay_counter++;      #if 0    /* 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) {    if (Pike_sp[-1].u.object->prog != null_program)    decode_error (data, NULL, "Placeholder object is not "    "a null_program clone.\n");    }    else if (Pike_sp[-1].type != T_INT ||    Pike_sp[-1].u.integer)    decode_error (data, NULL, "Expected placeholder object or zero "    "from __register_new_program.\n");    pop_stack(); -  } +    #endif       break;    }       case 4: /* New-style encoding. */    {    struct program *p;    ONERROR err;    ONERROR err2;
pike.git/src/encode.c:3924:       p->flags = p_flags;       /* Kludge to get end_first_pass() to free the program. */    Pike_compiler->num_parse_error++;       SET_ONERROR(err, cleanup_new_program_decode, NULL);       {    int fun = find_identifier("__register_new_program", -  data->codec->prog); +  decoder_codec (data)->prog);       if (fun >= 0) {    ref_push_program(p);    apply_low(data->codec, fun, 1);       /* Returned a placeholder */    if(Pike_sp[-1].type == T_OBJECT)    {    add_ref(c->placeholder=Pike_sp[-1].u.object);    if(c->placeholder->prog != null_program) {
pike.git/src/encode.c:4872: Inside #if defined(PIKE_DEBUG)
   if(data->unfinished_programs)    Pike_fatal("We have unfinished programs left in decode()!\n");    if(data->unfinished_objects)    Pike_fatal("We have unfinished objects left in decode()!\n");    if(data->unfinished_placeholders)    Pike_fatal("We have unfinished placeholders left in decode()!\n");    }   #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)    {    struct unfinished_prog_link *tmp=data->unfinished_programs;    data->unfinished_programs=tmp->next;    free((char *)tmp);    }       while(data->unfinished_objects)
pike.git/src/encode.c:4972: Inside #if defined(ENCODE_DEBUG)
  #ifdef ENCODE_DEBUG    , int debug   #endif    )   {    struct decode_data *data;    ONERROR err;       /* 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    ) {    struct svalue *res;    struct svalue val = SVALUE_INIT_INT (0);    val.u.integer = COUNTER_START;    if ((res = low_mapping_lookup(data->decoded, &val))) {    push_svalue(res);    return 1;
pike.git/src/encode.c:4998:       data=ALLOC_STRUCT(decode_data);    data->counter.type=T_INT;    data->counter.subtype=NUMBER_NUMBER;    data->counter.u.integer=COUNTER_START;    data->data_str = tmp;    data->data=(unsigned char *)tmp->str;    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;    data->unfinished_objects=0;    data->unfinished_placeholders = NULL;    data->delay_counter = 0;    data->raw = tmp;    data->next = current_decode;   #ifdef PIKE_THREADS    data->thread_state = Pike_interpreter.thread_state;
pike.git/src/encode.c:5029:    GETC() != 'e' ||    GETC() != '0')    {    free( (char *) data);    return 0;    }       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    SET_ONERROR(err, error_free_decode_data, data);      #if TWO_PASS_DECODE_WORKS    init_supporter(& data->supporter,    (supporter_callback *) re_decode,    (void *)data);   #endif
pike.git/src/encode.c:5321:      /*! @decl mixed decode_value(string coded_value, void|Codec codec)    *!    *! Decode a value from the string @[coded_value].    *!    *! This function takes a string created with @[encode_value()] or    *! @[encode_value_canonic()] and converts it back to the value that was    *! 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()]    */   void f_decode_value(INT32 args)   {    struct pike_string *s;    struct object *codec;      #ifdef ENCODE_DEBUG
pike.git/src/encode.c:5369:    MEMSET (&data, 0, sizeof (data));    data.data_str = s; /* Not refcounted. */    decode_error(&data, NULL,    "The codec may not be a subtyped object yet.\n");    }    codec = Pike_sp[1-args].u.object;    break;    }    /* 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   #ifdef ENCODE_DEBUG    , debug   #endif    ))    {    char *v=s->str;    ptrdiff_t l=s->len;