92ba302014-10-02Martin Nilsson /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
8cccac2014-08-28Per Hedbor #include "global.h"
540b6c2014-09-01Per Hedbor #include "fdlib.h" #include "pike_netlib.h"
8cccac2014-08-28Per Hedbor #include "object.h" #include "interpret.h" #include "operators.h" #include "bignum.h" #include "sscanf.h" #include "builtin_functions.h"
540b6c2014-09-01Per Hedbor #include "interpret.h"
3ecc992014-09-08Henrik Grubbström (Grubba) #include "cyclic.h"
540b6c2014-09-01Per Hedbor #include "backend.h" #include "fd_control.h" #include "file_machine.h" #include "file.h"
8cccac2014-08-28Per Hedbor #include "whitespace.h" #include "pike_types.h"
540b6c2014-09-01Per Hedbor #include "pike_threadlib.h"
9d3bdd2014-10-01Martin Nilsson #include "buffer.h"
8f08202014-08-28Per Hedbor #include "module_support.h"
f5a48f2015-05-16Arne Goedeke #include "bitvector.h"
8f08202014-08-28Per Hedbor 
9071e02014-10-30Martin Nilsson /* Includes <gmp.h> */ #include "bignum.h"
87aa2e2015-04-02Henrik Grubbström (Grubba) #ifdef HAVE_ARPA_INET_H
8cccac2014-08-28Per Hedbor #include <arpa/inet.h>
87aa2e2015-04-02Henrik Grubbström (Grubba) #endif /* HAVE_ARPA_INET_H */
8cccac2014-08-28Per Hedbor  #define DEFAULT_CMOD_STORAGE static DECLARATIONS
fbc3bf2014-09-08Per Hedbor struct sysmem { unsigned char *p; size_t size; };
8b141e2014-09-01Per Hedbor 
fbc3bf2014-09-08Per Hedbor static struct program *buffer_error_program;
8b141e2014-09-01Per Hedbor 
540b6c2014-09-01Per Hedbor /*! @module Stdio */
cb65012014-10-01Martin Nilsson /*! @class Buffer
8cccac2014-08-28Per Hedbor  *! *! A buffer to use as input or buffering when doing I/O. It is *! similar to @[String.Buffer], but can only contain 8bit data and is *! designed for protocol parsing. It is optimized for reading from *! the beginning and adding to the end, and will try to minimize the *! amount of data copying that is done. *!
8b141e2014-09-01Per Hedbor  *! The class maintains two separate offsets, one for reading and one *! for writing. The functions that add data all do so at the write *! offset (the end of the buffer), and reading is done from the read *! offset (the start of the buffer). *! *! The class can also be used to directly read from and write to *! filedescriptors if so desired. This eliminates at least one memory *! copy. *! *! @note
cb65012014-10-01Martin Nilsson  *! The "avoid copy" part means that a Buffer will never shrink
8b141e2014-09-01Per Hedbor  *! unless you call the @[trim] function. *!
8cccac2014-08-28Per Hedbor  */
cb65012014-10-01Martin Nilsson PIKECLASS Buffer
8cccac2014-08-28Per Hedbor {
50c7192014-09-10Per Hedbor #if PRECOMPILE_API_VERSION > 5 PIKEVAR int b.num_malloc; PIKEVAR int b.num_move; #endif
cb65012014-10-01Martin Nilsson  CVAR Buffer b;
3fe41e2014-09-12Marcus Cromnow 
c7607f2014-10-05Henrik Grubbström (Grubba)  EXTRA { PIKE_MAP_VARIABLE("__output", OFFSETOF(Buffer_struct, b.output), tMix, PIKE_T_MIXED, ID_PRIVATE|ID_HIDDEN|ID_PROTECTED); }
cb65012014-10-01Martin Nilsson  static void io_set_error_mode( Buffer *io, struct program *m )
8cccac2014-08-28Per Hedbor  {
929b282014-09-18Henrik Grubbström (Grubba)  if( m ) add_ref(m);
fbc3bf2014-09-08Per Hedbor  if( io->error_mode ) free_program( io->error_mode ); io->error_mode = m;
8cccac2014-08-28Per Hedbor  }
307d112015-11-21Arne Goedeke  PMOD_EXPORT Buffer *io_buffer_from_object(struct object *o) { return get_storage(o, Buffer_program);
8cccac2014-08-28Per Hedbor  }
307d112015-11-21Arne Goedeke 
cb65012014-10-01Martin Nilsson  static void io_unlock( Buffer *io )
8cccac2014-08-28Per Hedbor  { io->locked--; }
cb65012014-10-01Martin Nilsson  static void io_lock( Buffer *io )
8cccac2014-08-28Per Hedbor  { io->locked++; }
f3ed292014-09-11Per Hedbor  static void io_was_locked( ) ATTRIBUTE((noclone,noinline)); static void io_was_locked( )
8cccac2014-08-28Per Hedbor  { Pike_error("Can not modify the buffer right now, " " there are active subbuffers.\n"); }
cb65012014-10-01Martin Nilsson  static void io_ensure_unlocked(Buffer *io)
f3ed292014-09-11Per Hedbor  { if( io->locked ) io_was_locked( ); }
307d112015-11-21Arne Goedeke  PMOD_EXPORT void io_trim( Buffer *io )
9171842015-07-13Per Hedbor  ATTRIBUTE((noinline));
cb65012014-10-01Martin Nilsson  static int io_is_whitespace( Buffer *io, size_t pos )
8f08202014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  if( pos > io_len( io ) ) return -1; switch( io->buffer[io->offset+pos] ) { SPACECASE8 return 1; } return 0;
8f08202014-08-28Per Hedbor  }
307d112015-11-21Arne Goedeke  PMOD_EXPORT void io_trim( Buffer *io )
9171842015-07-13Per Hedbor  {
d408e32015-07-27Henrik Grubbström (Grubba)  if( io->malloced && (io->offset > 64 || io->len > 64) && !io->locked)
9171842015-07-13Per Hedbor  { if( io->offset > 64 && (!io->locked_move && (io->offset > io_len(io)))) { memmove( io->buffer, io_read_pointer(io), io_len(io) ); io->len -= io->offset; io->num_move++; io->offset = 0; } if( io->len > 64 && ((io->allocated > (io->len)*(1.0+io->max_waste)))) { io->buffer = xrealloc( io->buffer, io->len ); io->num_malloc++; io->allocated = io->len; } } }
cb65012014-10-01Martin Nilsson  static void io_unlink_external_storage( Buffer *io )
50c7192014-09-10Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static void io_unlink_external_storage( Buffer *io )
50c7192014-09-10Per Hedbor  { if( io->sub ) {
cb65012014-10-01Martin Nilsson  io_unlock( get_storage(io->sub,Buffer_program ) );
50c7192014-09-10Per Hedbor  free_object( io->sub ); } if( io->source ) free_object( io->source ); if( io->str ) free_string( io->str ); io->source = 0; io->sub = 0; io->str = 0; }
307d112015-11-21Arne Goedeke  PMOD_EXPORT void io_ensure_malloced( Buffer *io, size_t bytes )
fbc3bf2014-09-08Per Hedbor  { if( UNLIKELY(!io->malloced) )
8cccac2014-08-28Per Hedbor  { /* convert to malloced buffer from a shared one. */
9171842015-07-13Per Hedbor  unsigned char *old = io->buffer;
5a4dcd2015-05-16Arne Goedeke 
9171842015-07-13Per Hedbor  bytes += io->len;
5a4dcd2015-05-16Arne Goedeke 
9171842015-07-13Per Hedbor  if (bytes < io->len || bytes + 100 < bytes)
5a4dcd2015-05-16Arne Goedeke  Pike_error(msg_out_of_mem_2, bytes + 100);
9171842015-07-13Per Hedbor  bytes += 100;
5a4dcd2015-05-16Arne Goedeke 
9171842015-07-13Per Hedbor  io->buffer = xalloc( bytes ); io->malloced = 1; io->allocated = bytes; io->num_malloc++; memcpy( io->buffer, old, io->len ); io_unlink_external_storage(io);
8cccac2014-08-28Per Hedbor  }
fbc3bf2014-09-08Per Hedbor  }
8cccac2014-08-28Per Hedbor 
307d112015-11-21Arne Goedeke  PMOD_EXPORT unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )
f3ed292014-09-11Per Hedbor  ATTRIBUTE((noclone,noinline));
307d112015-11-21Arne Goedeke  PMOD_EXPORT unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )
fbc3bf2014-09-08Per Hedbor  {
4015132014-09-15Per Hedbor  if( bytes && io->len+bytes < io->len ) Pike_error("Too large buffer, can not have more than %lu bytes", (size_t)-1);
fbc3bf2014-09-08Per Hedbor  io_ensure_unlocked(io); io_ensure_malloced(io, bytes); /* * It is actually not certain that checking this is a good idea. * * The reason being that if the current buffer size is very small * (io_len(io)) and the bytes added is large and there is an * offset, it makes sense to move now when we do not have to copy * as much. * */ if( LIKELY(!io->locked_move) )
8cccac2014-08-28Per Hedbor  {
9171842015-07-13Per Hedbor  if( UNLIKELY((force && io->offset) || (io->offset > io->len)) )
fbc3bf2014-09-08Per Hedbor  {
9171842015-07-13Per Hedbor  /* more than 50% of the buffer is available before the read pointer, * and we can discard that data. Move the data to the beginning, making * room for more data. */
fbc3bf2014-09-08Per Hedbor  memmove( io->buffer, io_read_pointer(io), io_len(io) ); io->num_move++; io->len -= io->offset; io->offset = 0; }
8cccac2014-08-28Per Hedbor  }
317fc32014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  if( UNLIKELY(io->len + bytes > io->allocated) )
8cccac2014-08-28Per Hedbor  {
9171842015-07-13Per Hedbor  /* Actually grow the buffer. */ size_t growth = (io->allocated>>1) + (io->allocated>>3);/* io->allocated * 0.625 */
fbc3bf2014-09-08Per Hedbor 
9171842015-07-13Per Hedbor  if( growth < bytes ) growth = bytes + (bytes>>1);
fbc3bf2014-09-08Per Hedbor 
9171842015-07-13Per Hedbor  if( io->allocated + growth < io->allocated ) { growth = bytes+1; if( io->allocated + growth < io->allocated ) Pike_error("Overflow in buffer size calculations\n"); } io->buffer = xrealloc( io->buffer, io->allocated + growth );
fbc3bf2014-09-08Per Hedbor  io->num_malloc++;
9171842015-07-13Per Hedbor  io->allocated += growth;
8cccac2014-08-28Per Hedbor  } return io->buffer+io->len; }
317fc32014-09-02Per Hedbor  /*! @decl protected bool range_error( int howmuch ) *! *! This function is called when an attempt is made to read out of bounds. *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The default implementation simply returns @expr{0@} (zero).
317fc32014-09-02Per Hedbor  *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! Override this function to change the behavior. *! *! @param howmuch
317fc32014-09-02Per Hedbor  *! The argument @[howmuch] indicates how much data is needed: *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! @int *! @value 1.. *! Need @[howmuch] bytes more
611a8e2014-09-08Per Hedbor  *! @value 0
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The amount of data needed is not certain. *! This most often happens when @[sscanf] or @[read_json] is used *! @value ..-1 *! Tried to @[unread] -@[howmuch] bytes. There is usually no way to satisfy *! the requested range.
317fc32014-09-02Per Hedbor  *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The only supported way is to extract the data from the buffer, *! add the requested amount of "go backbuffer", add the data *! back, and forward -@[howmuch] bytes. *! @endint
317fc32014-09-02Per Hedbor  *! *! @returns *! *! @[true] if the operation should be retried, @[false] otherwise. *! *! Do not return true unless you have added data to the buffer, *! doing so could result in an infinite loop (since no data is *! added, the range_error will be called again immediately). */
89aecf2014-09-12Per Hedbor  PIKEFUN int(0..1) range_error( int range )
317fc32014-09-02Per Hedbor  flags ID_PROTECTED;
8cccac2014-08-28Per Hedbor  {
89aecf2014-09-12Per Hedbor  Pike_sp[-1].u.integer = 0;
317fc32014-09-02Per Hedbor  }
cb65012014-10-01Martin Nilsson  static void io_range_error_throw( Buffer *io, int howmuch )
fbc3bf2014-09-08Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static void io_range_error_throw( Buffer *io, int howmuch )
317fc32014-09-02Per Hedbor  {
c280fd2014-11-24Per Hedbor  if( io->error_mode ) { struct object *err; if( howmuch > 0 ) {
5e9fc02015-08-18Per Hedbor  push_static_text("Trying to read %d bytes outside allowed range\n");
c280fd2014-11-24Per Hedbor  push_int(howmuch); f_sprintf(2); } else
5e9fc02015-08-18Per Hedbor  push_static_text("Illegal arguments\n");
c280fd2014-11-24Per Hedbor  if( io->error_mode != buffer_error_program )
317fc32014-09-02Per Hedbor  {
c280fd2014-11-24Per Hedbor  ref_push_object( io->this ); err = clone_object(io->error_mode,2);
317fc32014-09-02Per Hedbor  }
c280fd2014-11-24Per Hedbor  else err = clone_object(io->error_mode,1); push_object(err); f_throw(1); }
317fc32014-09-02Per Hedbor  }
0d24ca2014-12-06Henrik Grubbström (Grubba)  static struct pike_string *io_read_string( Buffer *io, ptrdiff_t len )
fbc3bf2014-09-08Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static size_t io_rewind( Buffer *io, INT_TYPE n );
8923ca2014-09-03Per Hedbor 
fbc3bf2014-09-08Per Hedbor  static void io_do_rewind_on_error( struct rewind_to *e ) { e->io->locked_move--; e->io->offset = e->rewind_to; free( e ); }
cb65012014-10-01Martin Nilsson  static void io_rewind_on_error( Buffer *io, ONERROR *x )
fbc3bf2014-09-08Per Hedbor  { struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) );
5fc94a2014-09-14Henrik Grubbström (Grubba)  io->locked_move++;
fbc3bf2014-09-08Per Hedbor #if defined(PIKE_DEBUG) rew->old_locked_move = io->locked_move; #endif rew->io = io; rew->rewind_to = io->offset; SET_ONERROR( (*x), io_do_rewind_on_error, rew ); }
cb65012014-10-01Martin Nilsson  static void io_unset_rewind_on_error( Buffer *io, ONERROR *x )
fbc3bf2014-09-08Per Hedbor  {
50c7192014-09-10Per Hedbor  struct rewind_to *rew = x->arg;
2a41d42015-05-07Tobias S. Josefowitz #if defined(PIKE_DEBUG)
c000962014-09-08Henrik Grubbström (Grubba)  if( io->locked_move != rew->old_locked_move )
fbc3bf2014-09-08Per Hedbor  Pike_fatal( "Invalid io_rewind_on_error nesting\n");
50c7192014-09-10Per Hedbor #endif
2a41d42015-05-07Tobias S. Josefowitz  free( rew );
50c7192014-09-10Per Hedbor  UNSET_ONERROR( (*x) ); io->locked_move--;
fbc3bf2014-09-08Per Hedbor  } static void io_do_unwrite_on_error( struct rewind_to *e ) { e->io->len = e->rewind_to; free( e ); }
cb65012014-10-01Martin Nilsson  static void io_unwrite_on_error( Buffer *io, ONERROR *x )
fbc3bf2014-09-08Per Hedbor  { struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) ); rew->io = io; rew->rewind_to = io->len; SET_ONERROR( (*x), io_do_unwrite_on_error, rew ); }
cb65012014-10-01Martin Nilsson  static void io_unset_unwrite_on_error( Buffer *UNUSED(io), ONERROR *x )
fbc3bf2014-09-08Per Hedbor  { UNSET_ONERROR( (*x) ); free( x->arg ); }
c7607f2014-10-05Henrik Grubbström (Grubba)  static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun, ptrdiff_t nbytes )
50c7192014-09-10Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static void io_set_events( Buffer *io, struct my_file *fd, int extra, int set )
50c7192014-09-10Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static void io_set_events( Buffer *UNUSED(io), struct my_file *fd, int extra, int set )
50c7192014-09-10Per Hedbor  { fd->box.revents &= ~((1<<set)|extra); if(!SAFE_IS_ZERO(&fd->event_cbs[set]) && fd->box.backend) set_fd_callback_events(&fd->box, fd->box.events|(1<<set), 0); }
c7607f2014-10-05Henrik Grubbström (Grubba)  static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun, ptrdiff_t bytes )
50c7192014-09-10Per Hedbor  { if( bytes > 0 ) {
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t l = 0;
4529402015-07-14Per Hedbor  struct pike_string *s; io->locked_move++; s = io_read_string( io,bytes );
50c7192014-09-10Per Hedbor  if( s ) { io->output_triggered = 1; push_string( s );
c7607f2014-10-05Henrik Grubbström (Grubba)  apply_svalue( fun, 1 ); if (UNLIKELY(TYPEOF(Pike_sp[-1]) != PIKE_T_INT)) {
4529402015-07-14Per Hedbor  io->locked_move--;
c7607f2014-10-05Henrik Grubbström (Grubba)  Pike_error("Invalid return value from write callback.\n"); }
50c7192014-09-10Per Hedbor  l = Pike_sp[-1].u.integer; pop_stack();
c7607f2014-10-05Henrik Grubbström (Grubba)  if( l < 0 )
50c7192014-09-10Per Hedbor  {
4529402015-07-14Per Hedbor  io->locked_move--;
50c7192014-09-10Per Hedbor  io_rewind( io, bytes ); return -1; }
130baa2014-10-03Per Hedbor  if( bytes > l )
4529402015-07-14Per Hedbor  {
50c7192014-09-10Per Hedbor  io_rewind( io, bytes-l );
4529402015-07-14Per Hedbor  }
50c7192014-09-10Per Hedbor  }
4529402015-07-14Per Hedbor  io->locked_move--;
50c7192014-09-10Per Hedbor  return l; } return -1; }
0e68e62014-10-11Henrik Grubbström (Grubba)  static ptrdiff_t io_actually_trigger_output( Buffer *io )
7c34772014-09-11Per Hedbor  ATTRIBUTE((noclone,noinline));
0e68e62014-10-11Henrik Grubbström (Grubba)  static ptrdiff_t io_actually_trigger_output( Buffer *io )
8923ca2014-09-03Per Hedbor  {
c7607f2014-10-05Henrik Grubbström (Grubba)  struct program *prog; struct reference *ref; struct inherit *inh; if (UNLIKELY(!(prog = io->output.u.object->prog))) { /* Destructed object. */ free_svalue(&io->output); SET_SVAL(io->output, PIKE_T_INT, NUMBER_NUMBER, integer, 0);
0e68e62014-10-11Henrik Grubbström (Grubba)  return 0;
c7607f2014-10-05Henrik Grubbström (Grubba)  } ref = PTR_FROM_INT(prog, SUBTYPEOF(io->output)); inh = INHERIT_FROM_PTR(prog, ref); if ((inh->prog == file_program) && (ref->identifier_offset == fd_write_identifier_offset)) { /* Stdio.Fd::write */ struct my_file *fd = get_inherit_storage( io->output.u.object, ref->inherit_offset );
7c34772014-09-11Per Hedbor  io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE ); io->output_triggered = 1;
0e68e62014-10-11Henrik Grubbström (Grubba)  return 0;
50c7192014-09-10Per Hedbor  }
7c34772014-09-11Per Hedbor  else
0e68e62014-10-11Henrik Grubbström (Grubba)  return io_call_write( io, &io->output, MINIMUM( io_len(io), 100 ) );
7c34772014-09-11Per Hedbor  }
0e68e62014-10-11Henrik Grubbström (Grubba)  static ptrdiff_t io_trigger_output( Buffer *io )
7c34772014-09-11Per Hedbor  {
c7607f2014-10-05Henrik Grubbström (Grubba)  if( UNLIKELY(io->output.u.object) && UNLIKELY(!io->output_triggered) )
0e68e62014-10-11Henrik Grubbström (Grubba)  return io_actually_trigger_output(io); return 0;
8923ca2014-09-03Per Hedbor  }
cb65012014-10-01Martin Nilsson  static int io_range_error( Buffer *io, ptrdiff_t howmuch )
fbc3bf2014-09-08Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static int io_range_error( Buffer *io, ptrdiff_t howmuch )
317fc32014-09-02Per Hedbor  { int res; struct svalue *osp = Pike_sp;
fbc3bf2014-09-08Per Hedbor  push_int64( howmuch );
cb65012014-10-01Martin Nilsson  apply_current( f_Buffer_range_error_fun_num, 1 );
317fc32014-09-02Per Hedbor  res = Pike_sp[-1].u.integer; pop_n_elems( Pike_sp-osp ); if( !res ) io_range_error_throw( io, howmuch ); return res;
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  static int io_avail( Buffer *io, ptrdiff_t len )
8cccac2014-08-28Per Hedbor  {
ebd1d42014-09-14Per Hedbor  if( len < 0 || len + io->offset > io->len ) { if( len < 0 ) io_range_error_throw( io, 0 ); else if( io_range_error( io, len+io->len-io->offset ) ) return io_avail(io,len);
317fc32014-09-02Per Hedbor  return 0;
ebd1d42014-09-14Per Hedbor  }
8cccac2014-08-28Per Hedbor  return 1; }
cb65012014-10-01Martin Nilsson  static int io_avail_mul( Buffer *io, ptrdiff_t len, ptrdiff_t each )
fbc3bf2014-09-08Per Hedbor  { /* safely check if len*each is available. */
ebd1d42014-09-14Per Hedbor  size_t total = io_len(io); if( len < 0 || each <= 0 ) { io_range_error_throw( io, 0 ); return 0; } if( (total/(size_t)each) < (size_t)len ) { if( io_range_error( io, len+io->len-io->offset ) ) return io_avail_mul(io,len,each);
fbc3bf2014-09-08Per Hedbor  return 0;
ebd1d42014-09-14Per Hedbor  }
fbc3bf2014-09-08Per Hedbor  return 1; }
cb65012014-10-01Martin Nilsson  static void io_append( Buffer *io, const void *p, size_t bytes )
8cccac2014-08-28Per Hedbor  { memcpy( io_add_space( io, bytes, 0 ), p, bytes ); io->len += bytes;
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  static size_t io_read( Buffer *io, void *to, size_t len )
8cccac2014-08-28Per Hedbor  { if( !io_avail(io,len)) return 0; memcpy( to, io_read_pointer(io), len ); io_consume( io, len ); return len; }
0d24ca2014-12-06Henrik Grubbström (Grubba)  static struct pike_string *io_read_string( Buffer *io, ptrdiff_t len )
8cccac2014-08-28Per Hedbor  { struct pike_string *s; if( len > 0x7fffffff ) Pike_error("This region is too large to convert to a string.\n");
fbc3bf2014-09-08Per Hedbor 
4015132014-09-15Per Hedbor  if( len < 0 ) return make_shared_binary_string(NULL,0);
fbc3bf2014-09-08Per Hedbor  if( !io_avail(io,len)) return NULL;
8cccac2014-08-28Per Hedbor  s = begin_shared_string( len );
317fc32014-09-02Per Hedbor  io_read( io, s->str, len );
8cccac2014-08-28Per Hedbor  return end_shared_string(s); }
cb65012014-10-01Martin Nilsson  static struct object *io_read_buffer( Buffer *io, size_t len, int do_copy )
8cccac2014-08-28Per Hedbor  { struct object *b;
cb65012014-10-01Martin Nilsson  Buffer *to;
8cccac2014-08-28Per Hedbor  if( !io_avail(io,len)) return NULL;
cb65012014-10-01Martin Nilsson  b = low_clone( Buffer_program ); to = get_storage(b,Buffer_program);
8cccac2014-08-28Per Hedbor  io_lock( io ); to->buffer = io_read_pointer(io); to->len = len; to->sub = Pike_fp->current_object;
929b282014-09-18Henrik Grubbström (Grubba)  add_ref(to->sub);
8cccac2014-08-28Per Hedbor  io_consume( io, len ); if( do_copy )
fbc3bf2014-09-08Per Hedbor  io_ensure_malloced( to, 0 );
8cccac2014-08-28Per Hedbor  return b; }
cb65012014-10-01Martin Nilsson  static int io_read_byte_uc( Buffer *io )
8cccac2014-08-28Per Hedbor  { return io->buffer[io->offset++]; }
cb65012014-10-01Martin Nilsson  static INT_TYPE io_read_number_uc( Buffer *io, size_t len )
8cccac2014-08-28Per Hedbor  {
0a3c552016-05-09Martin Nilsson  INT_TYPE res = 0;
87afe02014-09-20Stephen R. van den Berg  while( LIKELY(len--) ) {
fbc3bf2014-09-08Per Hedbor  res <<= 8; res |= io_read_byte_uc(io); } return res;
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  static INT_TYPE io_read_signed_number_uc( Buffer *io, size_t len )
ae81d22014-09-18Per Hedbor  { INT_TYPE res = 0;
3443b82014-09-20Stephen R. van den Berg  if( LIKELY(len--) ) { res = (INT8)io_read_byte_uc(io); while( LIKELY(len--) ) { res <<= 8; res |= io_read_byte_uc(io); }
ae81d22014-09-18Per Hedbor  } return res; }
0a3c552016-05-09Martin Nilsson  static INT64 io_read_number( Buffer *io, size_t len )
8cccac2014-08-28Per Hedbor  {
0a3c552016-05-09Martin Nilsson  INT64 res;
ebd1d42014-09-14Per Hedbor  if( !io_avail(io, len) ) return -1;
00e28b2014-10-02Per Hedbor  /* ensure only leading 0:s */
82a99c2014-09-14Stephen R. van den Berg  for (; UNLIKELY(len > SIZEOF_INT_TYPE); len--) if( UNLIKELY(io_read_byte_uc(io)) ) Pike_error("Integer (%dbit) overflow.\n", SIZEOF_INT_TYPE*8); res = io_read_number_uc( io, len ); if ( UNLIKELY(res < 0) ) Pike_error("Signed (%dbit) overflow.\n", SIZEOF_INT_TYPE*8); return res;
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  static struct object *io_read_bignum( Buffer *io, size_t len )
8cccac2014-08-28Per Hedbor  {
ae81d22014-09-18Per Hedbor  struct object *o; MP_INT *i; unsigned char *p; if( !io_avail(io,len) ) return NULL;
c3982f2014-10-29Martin Nilsson  o = fast_clone_object(bignum_program);
ae81d22014-09-18Per Hedbor  i = (void*)o->storage; mpz_import( i, len, 1, 1, 0, 0, io_read_pointer(io) ); io_consume(io,len); return o;
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  static void io_add_bignum( Buffer *io, struct object *o, int width )
7c89442014-09-11Per Hedbor  ATTRIBUTE((noclone,noinline));
cb65012014-10-01Martin Nilsson  static void io_add_bignum( Buffer *io, struct object *o, int width )
8cccac2014-08-28Per Hedbor  {
ae81d22014-09-18Per Hedbor  MP_INT *i = (void*)o->storage; MP_INT tmp; int free;
7c89442014-09-11Per Hedbor  unsigned char*d; struct pike_string *s;
ae81d22014-09-18Per Hedbor  int pad = 0;
0d24ca2014-12-06Henrik Grubbström (Grubba)  ptrdiff_t bytes;
ae81d22014-09-18Per Hedbor  size_t exp;
fbc3bf2014-09-08Per Hedbor 
ae81d22014-09-18Per Hedbor  if( mpz_sgn( i ) < 0 ) { mpz_init( &tmp ); mpz_add_ui( &tmp, i, 1); pad = 0xff; i = &tmp; }
fbc3bf2014-09-08Per Hedbor 
ae81d22014-09-18Per Hedbor  bytes = (mpz_sizeinbase( i, 2 )+7) / 8;
fbc3bf2014-09-08Per Hedbor 
ae81d22014-09-18Per Hedbor  if( bytes > width )
fbc3bf2014-09-08Per Hedbor  Pike_error("Number too large to store in %d bits\n", width*8);
7c89442014-09-11Per Hedbor  d = io_add_space( io, width, 0 ); io->len += width;
ae81d22014-09-18Per Hedbor  if( width > bytes ) { memset( d, pad, width-bytes ); d += width-bytes; } mpz_export( d, &exp, 1, 1, 1, 0, i ); if( !exp ) { /* if i is 0 mpz_export will not write anything. Handle that by zeroing the byte that should have been written. */ #ifdef PIKE_DEBUG if( bytes != 1 ) Pike_fatal("Oddities abound\n"); #endif *d = pad; } if( pad )
fbc3bf2014-09-08Per Hedbor  {
ae81d22014-09-18Per Hedbor  while(exp--) *d++ ^= 0xff; /* pad, but that is 0xff */ mpz_clear(&tmp);
fbc3bf2014-09-08Per Hedbor  } }
cb65012014-10-01Martin Nilsson  static void io_add_int_uc( Buffer *io, ptrdiff_t i, size_t bytes )
fbc3bf2014-09-08Per Hedbor  {
73599d2014-09-08Per Hedbor  unsigned char *x = io->buffer+io->len;
8cccac2014-08-28Per Hedbor  io->len += bytes; while(bytes--) {
8b65362014-09-11Stephen R. van den Berg  x[bytes] = i;
8cccac2014-08-28Per Hedbor  i>>=8; }
fbc3bf2014-09-08Per Hedbor  }
cb65012014-10-01Martin Nilsson  static size_t io_add_int( Buffer *io, ptrdiff_t i, size_t bytes )
fbc3bf2014-09-08Per Hedbor  {
ae81d22014-09-18Per Hedbor  io_add_space(io, bytes, 0);
fbc3bf2014-09-08Per Hedbor  io_add_int_uc( io, i, bytes );
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  return io_len( io ); }
cb65012014-10-01Martin Nilsson  static size_t io_rewind( Buffer *io, INT_TYPE n )
8cccac2014-08-28Per Hedbor  {
ebd1d42014-09-14Per Hedbor  if( n < 0 || (io->offset < (unsigned)n) ) { if( n < 0 ) io_range_error_throw( io, 0 ); else if( io_range_error(io,-(long)(n-io->offset)) ) return io_rewind( io, n ); return -1; }
8cccac2014-08-28Per Hedbor  io->offset -= n;
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  return io->offset; }
cb65012014-10-01Martin Nilsson  static void io_append_byte_uc( Buffer *io, unsigned char byte )
342f562014-09-02Per Hedbor  { io->buffer[io->len++] = byte; }
cb65012014-10-01Martin Nilsson  static void io_append_short_uc( Buffer *io, unsigned short shrt )
342f562014-09-02Per Hedbor  {
8b9b552015-08-06Per Hedbor  set_unaligned16( io->buffer+io->len, htons(shrt));
86010b2015-08-03Henrik Grubbström (Grubba)  io->len+=2;
342f562014-09-02Per Hedbor  }
cb65012014-10-01Martin Nilsson  static void io_append_int_uc( Buffer *io, unsigned INT32 i )
342f562014-09-02Per Hedbor  {
8b9b552015-08-06Per Hedbor  set_unaligned32( io->buffer+io->len, htonl(i));
86010b2015-08-03Henrik Grubbström (Grubba)  io->len+=4;
342f562014-09-02Per Hedbor  }
fbc3bf2014-09-08Per Hedbor 
9e83072014-10-16Stephen R. van den Berg  static size_t io_svalue_len( Buffer *io, struct svalue *p )
fbc3bf2014-09-08Per Hedbor  {
9e83072014-10-16Stephen R. van den Berg  switch( TYPEOF(*p) ) { case PIKE_T_INT: return 1; case PIKE_T_STRING: if( !p->u.string->size_shift ) return p->u.string->len; break; case PIKE_T_ARRAY: { size_t len; struct array *argp = p->u.array; INT_TYPE i; DECLARE_CYCLIC(); if (BEGIN_CYCLIC(io, argp)) Pike_error("Attempt to append a cyclic array to a buffer.\n"); for(len=i=0; i<argp->size; i++ ) len += io_svalue_len( io, argp->item+i ); END_CYCLIC();
f3ed292014-09-11Per Hedbor  return len;
9e83072014-10-16Stephen R. van den Berg  } case PIKE_T_OBJECT: { size_t len; if( get_memory_object_memory( p->u.object, NULL, &len, NULL ) ) return len; break; }
50c7192014-09-10Per Hedbor  }
f3ed292014-09-11Per Hedbor  Pike_error("Illegal argument (not an 8bit string or 8bit buffer object)\n");
fbc3bf2014-09-08Per Hedbor  } /* NOTE: Can return negative integers. */
50c7192014-09-10Per Hedbor  static INT_TYPE get_small_int( struct svalue *s ) ATTRIBUTE((noclone,noinline));
342f562014-09-02Per Hedbor  static INT_TYPE get_small_int( struct svalue *s ) {
50c7192014-09-10Per Hedbor  if( LIKELY(TYPEOF(*s) == PIKE_T_INT) ) return s->u.integer; if( is_bignum_object_in_svalue( s ) ) { INT64 i64; if( int64_from_bignum( &i64, s->u.object ) ) return i64; Pike_error("Too big bignum, can not fit in indicated width\n"); } Pike_error("Non integer argument\n");
342f562014-09-02Per Hedbor  }
cb65012014-10-01Martin Nilsson  static void io_append_svalue( Buffer *io, struct svalue *p )
f3ed292014-09-11Per Hedbor  ATTRIBUTE((noinline));
cb65012014-10-01Martin Nilsson  static void io_append_svalue( Buffer *io, struct svalue *p )
fbc3bf2014-09-08Per Hedbor  { switch( TYPEOF(*p) ) { case PIKE_T_STRING: { struct pike_string *s = p->u.string;
973a692014-09-10Henrik Grubbström (Grubba)  if( !s->len ) return;
cb65012014-10-01Martin Nilsson  if( s->size_shift ) Pike_error("Buffer only handles 8bit data\n");
fbc3bf2014-09-08Per Hedbor  if( !io->buffer ) {
973a692014-09-10Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
cb65012014-10-01Martin Nilsson  if (io->str) Pike_fatal("Buffer with string but NULL buffer.\n");
973a692014-09-10Henrik Grubbström (Grubba) #endif
fbc3bf2014-09-08Per Hedbor  io->str = s; io->buffer = (unsigned char*)s->str; io->len = s->len;
929b282014-09-18Henrik Grubbström (Grubba)  add_ref(s);
e2bd312015-02-23Arne Goedeke  io_trigger_output( io );
fbc3bf2014-09-08Per Hedbor  } else io_append( io, s->str, s->len ); } break; case PIKE_T_ARRAY: { struct array *argp = p->u.array; INT_TYPE i;
3ecc992014-09-08Henrik Grubbström (Grubba)  DECLARE_CYCLIC(); if (BEGIN_CYCLIC(io, argp)) Pike_error("Attempt to append a cyclic array to a buffer.\n");
fbc3bf2014-09-08Per Hedbor  for(i=0; i<argp->size; i++ ) io_append_svalue( io, argp->item+i );
3ecc992014-09-08Henrik Grubbström (Grubba)  END_CYCLIC();
fbc3bf2014-09-08Per Hedbor  } break; case PIKE_T_OBJECT: {
f3ed292014-09-11Per Hedbor  size_t len; void *ptr; struct sysmem *s; enum memobj_type t = get_memory_object_memory( p->u.object, &ptr, &len, NULL ); if( !io->buffer && t==MEMOBJ_SYSTEM_MEMORY )
fbc3bf2014-09-08Per Hedbor  {
f3ed292014-09-11Per Hedbor  io->buffer = ptr; io->len = len; io->source = p->u.object;
929b282014-09-18Henrik Grubbström (Grubba)  add_ref(io->source);
f3ed292014-09-11Per Hedbor  return;
fbc3bf2014-09-08Per Hedbor  }
f3ed292014-09-11Per Hedbor  if( t != MEMOBJ_NONE ) io_append( io, ptr, len );
fbc3bf2014-09-08Per Hedbor  else
f3ed292014-09-11Per Hedbor  Pike_error("Unsupported argument type\n");
fbc3bf2014-09-08Per Hedbor  } break; case PIKE_T_INT: { unsigned char a = p->u.integer; io_append( io, &a, 1 ); } } }
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor #undef THIS
cb65012014-10-01Martin Nilsson #define THIS (&(((struct Buffer_struct *)Pike_fp->current_storage)->b))
342f562014-09-02Per Hedbor 
8cccac2014-08-28Per Hedbor  /* pike functions */
e168612014-10-01Henrik Grubbström (Grubba)  /*! @decl int(-1..) input_from( Stdio.Stream f, int|void nbytes )
8b141e2014-09-01Per Hedbor  *!
559c922014-09-03Per Hedbor  *! Read data from @[f] into this buffer. If @[nbytes] is not *! specified, read until there is no more data to read (currently).
317fc32014-09-02Per Hedbor  *!
e168612014-10-01Henrik Grubbström (Grubba)  *! Returns the amount of data that was read, or @expr{-1@} on *! read error.
317fc32014-09-02Per Hedbor  *! *! @note *! Please note that this funcition will read all data from the *! filedescriptor unless it's set to be non-blocking.
8b141e2014-09-01Per Hedbor  */
e168612014-10-01Henrik Grubbström (Grubba)  PIKEFUN int(-1..) input_from( object f, int|void _nbytes, int|void _once )
8b141e2014-09-01Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8b141e2014-09-01Per Hedbor  size_t sz = io_len( io );
559c922014-09-03Per Hedbor  size_t bread = 0, nbytes = (size_t)-1;
8b141e2014-09-01Per Hedbor  struct my_file *fd;
432a822014-09-04Per Hedbor  int once = 0;
8b141e2014-09-01Per Hedbor 
e2e5382015-04-25Henrik Grubbström (Grubba)  if( _nbytes ) {
559c922014-09-03Per Hedbor  nbytes = _nbytes->u.integer;
e168612014-10-01Henrik Grubbström (Grubba)  if (!nbytes) RETURN 0; }
559c922014-09-03Per Hedbor 
432a822014-09-04Per Hedbor  if( _once ) once = _once->u.integer;
8b141e2014-09-01Per Hedbor  if( (fd = get_storage( f, file_program )) ) { while( 1 ) { unsigned char *ptr = io_add_space( io, 4096, 0 ); int res;
559c922014-09-03Per Hedbor  res = fd_read( fd->box.fd, ptr, MINIMUM(4096,nbytes) );
8b141e2014-09-01Per Hedbor  if( res == -1 && errno == EINTR ) continue; if( res <= 0 ) break;
432a822014-09-04Per Hedbor 
559c922014-09-03Per Hedbor  nbytes -= res;
8b141e2014-09-01Per Hedbor  io->len += res; bread += res;
e168612014-10-01Henrik Grubbström (Grubba)  if( res != 4096 || once || !nbytes )
8b141e2014-09-01Per Hedbor  break; }
50c7192014-09-10Per Hedbor  io_set_events( io, fd, PIKE_BIT_FD_READ_OOB, PIKE_FD_READ );
8b141e2014-09-01Per Hedbor  } else {
559c922014-09-03Per Hedbor  /* some other object. Just call read */ while( nbytes )
8b141e2014-09-01Per Hedbor  {
559c922014-09-03Per Hedbor  push_int( MINIMUM(4096,nbytes) );
8b141e2014-09-01Per Hedbor  safe_apply( f, "read", 1 ); if( TYPEOF(Pike_sp[-1]) != PIKE_T_STRING || Pike_sp[-1].u.string->len == 0 ) break; if( Pike_sp[-1].u.string->size_shift ) Pike_error("Can not handle non-8bit data\n"); io_append( io, Pike_sp[-1].u.string->str, Pike_sp[-1].u.string->len );
559c922014-09-03Per Hedbor  nbytes -= Pike_sp[-1].u.string->len;
8b141e2014-09-01Per Hedbor  pop_stack(); } }
e168612014-10-01Henrik Grubbström (Grubba)  if (!bread) RETURN -1;
8b141e2014-09-01Per Hedbor  RETURN bread; }
c7607f2014-10-05Henrik Grubbström (Grubba)  /*! @decl int __fd_set_output( object|function(string:int) write_callback )
8923ca2014-09-03Per Hedbor  *! *! This tells the buffer to trigger the write callback for the *! specified filedescriptor when data is added to the buffer. *! *! This is used internally by Stdio.File to handle nonblocking *! buffered mode, and is not really intended to be used directly.
fbc3bf2014-09-08Per Hedbor  *!
c7607f2014-10-05Henrik Grubbström (Grubba)  *! If @[write_callback] is @expr{0@} (zero) the state is cleared.
8923ca2014-09-03Per Hedbor  */
ecee5c2016-05-27Per Hedbor  PIKEFUN void __fd_set_output( zero|object|function f )
8923ca2014-09-03Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
c7607f2014-10-05Henrik Grubbström (Grubba)  if( TYPEOF(*f) == PIKE_T_OBJECT ) { struct program *p = f->u.object->prog; if (p) { struct inherit *inh = p->inherits + SUBTYPEOF(*f); int write_fun_num; p = inh->prog; if ((write_fun_num = find_identifier("write", p)) == -1) { Pike_error("Function \"write\" not available in object.\n"); } SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num); } } else if (TYPEOF(*f) != PIKE_T_FUNCTION) { push_int(0); f = Pike_sp-1;
50c7192014-09-10Per Hedbor  }
c7607f2014-10-05Henrik Grubbström (Grubba)  assign_svalue(&io->output, f); io->output_triggered = 0;
8923ca2014-09-03Per Hedbor  }
c7607f2014-10-05Henrik Grubbström (Grubba)  /*! @decl int(-1..) output_to( Stdio.Stream|function(string:int) fun, @ *! int(0..)|void nbytes )
540b6c2014-09-01Per Hedbor  *! *! Write data from the buffer to the indicated file. *!
c7607f2014-10-05Henrik Grubbström (Grubba)  *! @param fun *! Write function. Either one of: *! @mixed *! @type Stdio.Stream *! A file object in which the function @expr{write()@} will *! be called. *! @type function(string:int) *! A function which will be called with a @expr{string(8bit)@} *! to write and is expected to return an @expr{int@} indicating *! the number of bytes successfully written or @expr{-1@} on *! failure. *! @endmixed *!
2062be2014-09-09Henrik Grubbström (Grubba)  *! @param nbytes
c7607f2014-10-05Henrik Grubbström (Grubba)  *! If @[nbytes] is not specified the whole buffer will be written *! if possible. Otherwise at most @[nbytes] will be written.
2062be2014-09-09Henrik Grubbström (Grubba)  *! *! @returns
b064882014-09-11Stephen R. van den Berg  *! Will return the number of bytes that have been written successfully.
2062be2014-09-09Henrik Grubbström (Grubba)  *!
c7607f2014-10-05Henrik Grubbström (Grubba)  *! If no bytes have been written successfully and @expr{fun()@} failed
b064882014-09-11Stephen R. van den Berg  *! with an error, @expr{-1@} will be returned.
540b6c2014-09-01Per Hedbor  */
c7607f2014-10-05Henrik Grubbström (Grubba)  PIKEFUN int(-1..) output_to( object|function(string:int) f, int|void nbytes )
540b6c2014-09-01Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
04a10d2014-10-02Martin Nilsson  ptrdiff_t written = 0;
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t sz = io_len( io );
c7607f2014-10-05Henrik Grubbström (Grubba)  int write_fun_num = -1;
fbc3bf2014-09-08Per Hedbor 
559c922014-09-03Per Hedbor  if( !sz )
cd79ef2014-09-03Per Hedbor  {
50c7192014-09-10Per Hedbor  io_range_error(io, sz); sz = io_len(io);
cd79ef2014-09-03Per Hedbor  }
e2e5382015-04-25Henrik Grubbström (Grubba)  if( nbytes )
04a10d2014-10-02Martin Nilsson  sz = MINIMUM(nbytes->u.integer, sz);
559c922014-09-03Per Hedbor 
c7607f2014-10-05Henrik Grubbström (Grubba)  if( TYPEOF(*f) == PIKE_T_OBJECT ) { struct program *p = f->u.object->prog; if (LIKELY(p)) { struct inherit *inh = p->inherits + SUBTYPEOF(*f); p = inh->prog; if ((write_fun_num = find_identifier("write", p)) == -1) { Pike_error("Function \"write\" not available in object.\n"); } SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num); } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("output_to", 1, "object|function");
c7607f2014-10-05Henrik Grubbström (Grubba)  } } else if (UNLIKELY(TYPEOF(*f) != PIKE_T_FUNCTION)) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("output_to", 1, "object|function");
c7607f2014-10-05Henrik Grubbström (Grubba)  } else { write_fun_num = SUBTYPEOF(*f); } if (write_fun_num != FUNCTION_BUILTIN) { struct program *prog = f->u.object->prog; struct reference *ref = PTR_FROM_INT(prog, write_fun_num); struct inherit *inh = INHERIT_FROM_PTR(prog, ref); if( (inh->prog == file_program) && (ref->identifier_offset == fd_write_identifier_offset) ) { struct my_file *fd = get_inherit_storage( f->u.object, ref->inherit_offset ); while( sz > written ) { ptrdiff_t rd = MINIMUM(sz-written,4096); unsigned char *ptr = io_read_pointer( io ); ptrdiff_t res; res = fd_write( fd->box.fd, ptr, rd ); if( res == -1 && errno == EINTR ) continue; if( res <= 0 ) { fd->my_errno = errno; if (!written) written = -1; break; } io_consume( io, res ); written += res; io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE); } RETURN written;
540b6c2014-09-01Per Hedbor  } }
c7607f2014-10-05Henrik Grubbström (Grubba)  /* Some other object or function. Just call it. */ while( sz > written )
540b6c2014-09-01Per Hedbor  {
c7607f2014-10-05Henrik Grubbström (Grubba)  size_t rd = MINIMUM(sz-written,4096); ptrdiff_t wr = io_call_write( io, f, rd ); if( wr <= 0 )
540b6c2014-09-01Per Hedbor  {
c7607f2014-10-05Henrik Grubbström (Grubba)  if (!written) written = -1; break;
540b6c2014-09-01Per Hedbor  }
c7607f2014-10-05Henrik Grubbström (Grubba)  written += wr; if( wr < 4096 ) break;
540b6c2014-09-01Per Hedbor  } RETURN written; }
0e68e62014-10-11Henrik Grubbström (Grubba)  /*! @decl int(-1..) try_output() *! *! Try to write some data from the buffer to the file *! registered with @[__fd_set_output()]. *! *! This is typically called from backend callbacks when it *! seems that it is possible to write some data to the file. *! *! @returns *! Returns @expr{-1@} on write error, and otherwise *! the number of bytes written to the file. *! *! @seealso *! @[__fd_set_output()] */ PIKEFUN int(-1..) try_output() { Buffer *io = THIS; if (LIKELY(io->output.u.object) && LIKELY(!io->output_triggered)) RETURN io_actually_trigger_output(io); RETURN 0; }
ae81d22014-09-18Per Hedbor  /*! @decl int read_sint( int size ) *! *! Read a network byte order two:s complement signed number of size n*8 bits, then *! return it. *! *! Will return UNDEFINED if there is not enough buffer space *! available unless error mode is set to throw errors. */ PIKEFUN int read_sint( int nbytes ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
ae81d22014-09-18Per Hedbor  struct pike_string *tmp; Pike_sp--; if( !io_avail( io, nbytes ) ) { push_undefined(); return; } if( nbytes <= SIZEOF_INT_TYPE ) { push_int( io_read_signed_number_uc( io,nbytes ) ); return; } // It's a bignum. // We should probably optimize this. :) tmp = io_read_string( io, nbytes ); if( tmp->str[0]&0x80 ) { push_int(-1); push_int( nbytes * 8 ); o_lsh(); } ref_push_string( tmp ); push_int( 256 );
c3982f2014-10-29Martin Nilsson  push_object( clone_object( bignum_program, 2 ) );
ae81d22014-09-18Per Hedbor  if( tmp->str[0]&0x80 ) o_xor(); free_string( tmp ); }
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) _size_object( )
8cccac2014-08-28Per Hedbor  {
9171842015-07-13Per Hedbor  RETURN THIS->malloced ? THIS->allocated : 0;
8cccac2014-08-28Per Hedbor  }
adc3f12015-05-15Tobias S. Josefowitz  /*! @decl Buffer add_padding( int(0..) nbytes, int(0..255)|void byte )
ae81d22014-09-18Per Hedbor  *! *! Add @[nbytes] bytes of padding, if @[byte] is not specified the *! area will be filled with 0's, otherwise the specified byte will *! be repeated. */
adc3f12015-05-15Tobias S. Josefowitz  PIKEFUN Buffer add_padding( int(0..) nbytes, int|void _byte )
ae81d22014-09-18Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
ae81d22014-09-18Per Hedbor  int byte = 0; if( _byte ) byte = _byte->u.integer;
adc3f12015-05-15Tobias S. Josefowitz  if( nbytes < 0 ) Pike_error("Cannot add negative padding.\n");
ae81d22014-09-18Per Hedbor  memset( io_add_space( io, nbytes,0), byte, nbytes );
4241802015-05-15Tobias S. Josefowitz  io->len += nbytes;
ae81d22014-09-18Per Hedbor  Pike_sp -= args; ref_push_object( io->this ); }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer add( AddArgument ... data )
fbc3bf2014-09-08Per Hedbor  *! @code
cb65012014-10-01Martin Nilsson  *! private typedef @[System.Memory]|@[Stdio.Buffer]|@[String.Buffer] BufferObject;
fbc3bf2014-09-08Per Hedbor  *! private typedef BufferObject|string(8bit)|int(8bit)|array(AddArgument) AddArgument; *! @endcode
8cccac2014-08-28Per Hedbor  *!
8b141e2014-09-01Per Hedbor  *! Add the items in data to the end of the buffer.
fbc3bf2014-09-08Per Hedbor  *! *! The supported argument types are: *!
d4c85e2014-09-08Henrik Grubbström (Grubba)  *! @mixed
ecee5c2016-05-27Per Hedbor  *! @type string(8bit)
d4c85e2014-09-08Henrik Grubbström (Grubba)  *! An eight bit string.
ecee5c2016-05-27Per Hedbor  *! @type int(8bit)
d4c85e2014-09-08Henrik Grubbström (Grubba)  *! A single byte *! @type System.Memory *! A chunk of memory. The whole memory area is added.
cb65012014-10-01Martin Nilsson  *! @type Stdio.Buffer
d4c85e2014-09-08Henrik Grubbström (Grubba)  *! A chunk of memory. The whole memory area is added. *! @type String.Buffer *! A chunk of memory. The whole memory area is added. *! @type array(AddArgument) *! Add all elements in the array individually. Each element may be *! any one of the types listed here. *! @endmixed
8b141e2014-09-01Per Hedbor  *!
342f562014-09-02Per Hedbor  *! @seealso
8b141e2014-09-01Per Hedbor  *! @[sprintf], @[add_int8], @[add_int16], @[add_int32], @[add_int] *! and *! @[add_hstring]
8cccac2014-08-28Per Hedbor  */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add( object|string|int|array(object|string|int) ... argp)
8cccac2014-08-28Per Hedbor  { int i;
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
fbc3bf2014-09-08Per Hedbor 
8cccac2014-08-28Per Hedbor  for(i=0; i<args; i++ )
fbc3bf2014-09-08Per Hedbor  io_append_svalue( io, argp+i );
8b141e2014-09-01Per Hedbor 
fbc3bf2014-09-08Per Hedbor  pop_stack();
317fc32014-09-02Per Hedbor  ref_push_object(io->this);
8cccac2014-08-28Per Hedbor  }
ecee5c2016-05-27Per Hedbor  /*! @decl Buffer add_int8( int(8bit) )
8cccac2014-08-28Per Hedbor  *! Adds a single byte to the buffer. */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_int8( int i )
8cccac2014-08-28Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
f3ed292014-09-11Per Hedbor  *io_add_space(io,1,0)=i; io->len++; Pike_sp--;
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
ecee5c2016-05-27Per Hedbor  /*! @decl Buffer add_int16( int(16bit) )
8cccac2014-08-28Per Hedbor  *! *! Add a 16-bit network byte order value to the buffer */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_int16( int i )
8cccac2014-08-28Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
f3ed292014-09-11Per Hedbor  unsigned char *p = io_add_space(io,2,0); p[0] = i>>8; p[1] = i; io->len += 2;
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer add_int32( int i )
8cccac2014-08-28Per Hedbor  *! Adds a 32 bit network byte order value to the buffer */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_int32( int i )
8cccac2014-08-28Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
f3ed292014-09-11Per Hedbor  unsigned char *p = io_add_space(io,4,0); p[0] = i>>24; p[1] = i>>16; p[2] = i>>8; p[3] = i; io->len += 4;
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
292c782016-06-09Henrik Grubbström (Grubba)  /*! @decl Buffer add_int32( Gmp.mpz i ) *! Adds a 32 bit network byte order value to the buffer */ PIKEFUN Buffer add_int32( object mpz ) { INT64 i = 0; Buffer *io = THIS; unsigned char *p = io_add_space(io,4,0); if (!int64_from_bignum(&i, mpz)) { SIMPLE_ARG_TYPE_ERROR("add_int32", 1, "int|Gmp.mpz"); } p[0] = i>>24; p[1] = i>>16; p[2] = i>>8; p[3] = i; io->len += 4; ref_push_object(Pike_fp->current_object); }
ecee5c2016-05-27Per Hedbor  /*! @decl Buffer add_hstring( string(8bit) data, int size_size )
cb65012014-10-01Martin Nilsson  *! @decl Buffer add_hstring( Stdio.Buffer data, int size_size ) *! @decl Buffer add_hstring( System.Memory data, int size_size ) *! @decl Buffer add_hstring( String.Buffer data, int size_size )
ecee5c2016-05-27Per Hedbor  *! @decl Buffer add_hstring( int(8bit) data, int size_size )
cb65012014-10-01Martin Nilsson  *! @decl Buffer add_hstring( array data, int size_size )
ecee5c2016-05-27Per Hedbor  *! @decl Buffer add_hstring( int|string(8bit)|Stdio.Buffer|System.Memory|array data, int size_size, int offset )
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! Adds length of data followed by @[data] to the buffer.
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! This is identical to
f8c6fc2014-10-19Henrik Grubbström (Grubba)  *! @tt{sprintf("%"+size_size+"H",(string)Stdio.Buffer(data))@} but
50c7192014-09-10Per Hedbor  *! significantly faster.
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! @[size_size] is the number of bytes used to represent the length of the data. *! It must be less than Int.NATIVE_MAX. *!
adca9c2014-09-29Stephen R. van den Berg  *! @[offset] is added to the length of the data prior to writing out *! the length. Typical usage involves adding @[size_size] to account *! for the room used by the size. *!
50c7192014-09-10Per Hedbor  *! The supported @[data] argument types are *! *! @mixed
ecee5c2016-05-27Per Hedbor  *! @type int(8bit)
adca9c2014-09-29Stephen R. van den Berg  *! An eight bit character.
ecee5c2016-05-27Per Hedbor  *! @type string(8bit)
50c7192014-09-10Per Hedbor  *! An eight bit string. *! @type System.Memory *! A chunk of memory. The whole memory area is added.
cb65012014-10-01Martin Nilsson  *! @type Stdio.Buffer
50c7192014-09-10Per Hedbor  *! A chunk of memory. The whole memory area is added. *! @type String.Buffer *! A chunk of memory. The whole memory area is added. *! @type array *! Add all elements in the array individually. Each element may be *! any one of the types listed here. *! @endmixed
8cccac2014-08-28Per Hedbor  */
fbc3bf2014-09-08Per Hedbor 
d7ec8f2014-09-30Per Hedbor  /* we can not use the actual type here. the reason is that this class is loaded before the master is, so we cannot possibly use things that require the master (such as resolving things.) */
adca9c2014-09-29Stephen R. van den Berg  PIKEFUN Buffer add_hstring( int|string|object|array(int|string|Buffer|array) str, int size_size, void|int offset )
fbc3bf2014-09-08Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
50c7192014-09-10Per Hedbor  size_t len = io_svalue_len(io, str);
fbc3bf2014-09-08Per Hedbor 
adca9c2014-09-29Stephen R. van den Berg  if( offset ) len += offset->u.integer;
50c7192014-09-10Per Hedbor  if( size_size < (int)sizeof(size_t) &&
fbc3bf2014-09-08Per Hedbor  len > (((size_t)1)<<(8*size_size))-1 ) Pike_error("Too long string, need larger size field\n"); io_add_int( io, len, size_size );
50c7192014-09-10Per Hedbor  io_append_svalue( io, str );
9fc2ef2014-09-08Per Hedbor  pop_n_elems(args);
fbc3bf2014-09-08Per Hedbor  ref_push_object(io->this); }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer add_int( int i, int(0..) width )
8cccac2014-08-28Per Hedbor  *! *! Adds a generic integer to the buffer as an (width*8)bit *! network byteorder number. *! *! @[width] must be less than Int.NATIVE_MAX. *! */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_int( object|int i, int width )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  pop_stack(); /* width */
f3ed292014-09-11Per Hedbor  if( TYPEOF(*i) == PIKE_T_INT ) { io_add_int( THIS, i->u.integer, width ); Pike_sp--; } else { convert_stack_top_to_bignum(); io_add_bignum( THIS, i->u.object, width ); pop_stack(); /* o. */ }
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer add_hint( int i, int(0..) size_width )
3a3c822014-09-25Per Hedbor  *! *! First add the size of the integer when encoded to base 256 as a *! @[size_width] integer, then add the integer to the buffer, both *! in network byte order. *! *! @[size_width] must be less than Int.NATIVE_MAX. *! */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_hint( object|int i, int len_width )
3a3c822014-09-25Per Hedbor  { int width; pop_stack(); /* width */ if( TYPEOF(*i) == PIKE_T_INT ) { INT_TYPE ui = i->u.integer;
4726122015-05-02Henrik Grubbström (Grubba)  if (!ui) { io_add_int( THIS, 0, len_width ); } else { for( width=1; width<SIZEOF_INT_TYPE; width++ ) if( ui < (((INT_TYPE)1)<<(width*8)) && ui >= -(((INT_TYPE)1)<<(width*8-1)) ) break; io_add_int( THIS, width, len_width ); io_add_int( THIS, i->u.integer, width ); }
3a3c822014-09-25Per Hedbor  Pike_sp--; } else { convert_stack_top_to_bignum(); width = (mpz_sizeinbase( (void*)i->u.object->storage, 2)+7)/8; io_add_int( THIS, width, len_width ); io_add_bignum( THIS, i->u.object, width ); pop_stack(); /* o. */ } ref_push_object(Pike_fp->current_object); }
ecee5c2016-05-27Per Hedbor  /*! @decl Buffer add_ints( array(int) integers, int(8bit) len )
342f562014-09-02Per Hedbor  *! *! Add the integers in the specified array, @[len] bytes per int.
fbc3bf2014-09-08Per Hedbor  *! Equivalent to calling @[add_int] for each integer, but faster, *! and if an error occurs the buffer will contain no new *! data. Either all or none of the integers will be added. *! *! Errors can occur if one of the elements in @[integers] is not *! actually an integer, if sizeof(integers)*len is bigger than can *! be represented in a size_t, or if the buffer cannot grow due to *! an out of memory condition.
342f562014-09-02Per Hedbor  */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer add_ints( array(int) a, int bpi )
342f562014-09-02Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  int i,l = a->size; struct svalue *it = a->item; unsigned char *ptr;
130baa2014-10-03Per Hedbor  ptrdiff_t n=0;
fbc3bf2014-09-08Per Hedbor  ONERROR e;
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  io_unwrite_on_error(io, &e);
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  if( bpi < 0 ) Pike_error("Illegal int width\n");
130baa2014-10-03Per Hedbor #if SIZEOF_LONG == 4 if( DO_INT32_MUL_OVERFLOW( l, bpi, &n ) )
fbc3bf2014-09-08Per Hedbor #else
50c7192014-09-10Per Hedbor  if( DO_INT64_MUL_OVERFLOW( l, bpi, &n ) )
fbc3bf2014-09-08Per Hedbor #endif
5944b32014-09-11Henrik Grubbström (Grubba)  Pike_error("Result size exceeds ptrdiff_t size\n");
fbc3bf2014-09-08Per Hedbor  io_add_space( io, n, 0 ); switch( bpi ) {
50c7192014-09-10Per Hedbor  case 1: for( i=0; i<l; i++ ) io_append_byte_uc( io, get_small_int(it+i) ); break; case 2: for( i=0; i<l; i++ ) io_append_short_uc( io, get_small_int(it+i) ); break; case 4: for( i=0; i<l; i++ ) io_append_int_uc( io, get_small_int(it+i) ); break; case 3:
342f562014-09-02Per Hedbor #if SIZEOF_INT_TYPE > 4
50c7192014-09-10Per Hedbor  case 5: case 6: case 7:
342f562014-09-02Per Hedbor #endif
50c7192014-09-10Per Hedbor  for( i=0; i<l; i++ )
fbc3bf2014-09-08Per Hedbor  io_add_int_uc( io, get_small_int(it+i), bpi ); break; default: /* bignums. */ for( i=0; i<l; i++ ) {
50c7192014-09-10Per Hedbor  if( LIKELY(TYPEOF(it[i]) == PIKE_T_INT) ) io_add_int_uc( io, it[i].u.integer, bpi); else if( LIKELY(TYPEOF(it[i]) == PIKE_T_OBJECT) ) io_add_bignum( io, it[i].u.object, bpi ); else Pike_error("Illegal argument.\n");
fbc3bf2014-09-08Per Hedbor  } } io_unset_unwrite_on_error( io, &e ); io_trigger_output( io );
50c7192014-09-10Per Hedbor  Pike_sp--; pop_stack();
fbc3bf2014-09-08Per Hedbor  ref_push_object(io->this);
342f562014-09-02Per Hedbor  }
8cccac2014-08-28Per Hedbor  /*! @decl protected int `[](int off) *! *! Return the character at the specified offset. */
ecee5c2016-05-27Per Hedbor  PIKEFUN int(8bit) `[]( int off )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8cccac2014-08-28Per Hedbor  if( off < 0 ) off = io_len(io)-off; if( io_avail( io, off ) )
89aecf2014-09-12Per Hedbor  Pike_sp[-1].u.integer = io_read_pointer(io)[off];
8cccac2014-08-28Per Hedbor  else
89aecf2014-09-12Per Hedbor  Pike_sp[-1].u.integer = -1;
8cccac2014-08-28Per Hedbor  } /*! @decl protected int `[]=(int off, int char) *! *! Set the character at the specified offset to @[char]. */
ecee5c2016-05-27Per Hedbor  PIKEFUN int(8bit) `[]=( int off, int val )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
89aecf2014-09-12Per Hedbor 
fbc3bf2014-09-08Per Hedbor  io_ensure_malloced( io, 0 );
8cccac2014-08-28Per Hedbor  if( off < 0 ) off = io_len(io)-off;
89aecf2014-09-12Per Hedbor  again:
8cccac2014-08-28Per Hedbor  if( io_avail( io, off ) ) { io_read_pointer(io)[off]=(val&0xff); } else {
89aecf2014-09-12Per Hedbor  /* hm, well. We could extend the buffer. Should we? */ if( io_range_error(io, off ) ) goto again; Pike_error("Writing outside buffer\n");
8cccac2014-08-28Per Hedbor  } } /*! @decl int _sizeof() *! *! Returns the buffer size, in bytes. *! This is how much you can read from the buffer until it runs out of data. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) _sizeof()
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; { push_int64(io_len(THIS)); } /*! @decl string cast(string type) *! *! Convert the buffer to a string. *! *!@note *! This only works for buffers whose length is less than 0x7fffffff. */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) cast(string to)
2f7cd22014-12-01Martin Nilsson  flags ID_PROTECTED;
8cccac2014-08-28Per Hedbor  { if( to != literal_string_string ) { push_undefined(); return; } if( io_len(THIS) > 0x7fffffff ) Pike_error("This buffer is too large to convert to a string.\n"); push_string(make_shared_binary_string((void*)io_read_pointer(THIS), (INT32)io_len(THIS))); }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer set_error_mode(int m) *! @decl Buffer set_error_mode(program m)
8cccac2014-08-28Per Hedbor  *! *! Set the error mode of this buffer to @[m]. *!
9629ad2014-09-01Per Hedbor  *! If true operations that would normally return 0 (like trying to *! read too much) will instead throw an error. If @[m] is a program *! a clone of it will be thrown on error.
8cccac2014-08-28Per Hedbor  *! *! This is useful when parsing received data, you do not have to *! verify that each and every read operation suceeds. *! *! However, the non-error mode is more useful when checking to see *! if a packet/segment/whatever has arrived. *! *! The thrown error object will have the constant buffer_error set *! to a non-false value. *! *! @example *! @code *! void read_callback(int i, string new_data) *! { *! inbuffer->add( new_data ); *!
cb65012014-10-01Martin Nilsson  *! while( Buffer packet = inbuffer->read_hbuffer(2) )
8cccac2014-08-28Per Hedbor  *! { *! packet->set_error_mode(Buffer.THROW_ERROR); *! if( mixed e = catch( handle_packet( packet ) ) ) *! if( e->buffer_error ) *! protocol_error(); // illegal data in packet *! else *! throw(e); // the other code did something bad *! } *! } *! *!
cb65012014-10-01Martin Nilsson  *! void handle_packet( Buffer pack )
8cccac2014-08-28Per Hedbor  *! { *! switch( pack->read_int8() ) *! { *! ... *! case HEADER_FRAME: *! int num_headers = pack->read_int32(); *! for( int i = 0; i<num_headers; i++ ) *! headers[pack->read_hstring(2)] = pack->read_hstring(2); *! ... *! } *! } *! @endcode */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer set_error_mode( int|program m )
8cccac2014-08-28Per Hedbor  {
89aecf2014-09-12Per Hedbor  if( TYPEOF(*m) == PIKE_T_INT ) io_set_error_mode( THIS, m->u.integer ? buffer_error_program : 0 ); else io_set_error_mode( THIS, program_from_svalue(m)); pop_stack();
fbc3bf2014-09-08Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  } /*! @decl object lock() *! *! Makes this buffer read only until the returned object is released. *! *! @note *! This currently simply returns a 0-length subbuffer. */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer lock()
8cccac2014-08-28Per Hedbor  { push_object( io_read_buffer( THIS, 0, 0 ) ); }
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) _sprintf(int o, mapping UNUSED)
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; {
71050c2014-11-26Henrik Grubbström (Grubba)  size_t bytes;
89aecf2014-09-12Per Hedbor  pop_n_elems(args-1); Pike_sp--; switch( o )
8cccac2014-08-28Per Hedbor  {
89aecf2014-09-12Per Hedbor  case 'O': {
5e9fc02015-08-18Per Hedbor  push_static_text("%O(%d bytes, read=[..%d] data=[%d..%d] free=[%d..%d] %s%s)");
89aecf2014-09-12Per Hedbor  ref_push_program(Pike_fp->current_object->prog); /* io_len [..offset] [offset..len] [..allocated] */ push_int(io_len(THIS)); push_int(THIS->offset-1); push_int(THIS->offset); push_int(THIS->len-1); push_int(THIS->len); push_int(THIS->allocated);
5e9fc02015-08-18Per Hedbor  push_static_text( (THIS->str ? "string" : THIS->malloced ? "allocated" : "subbuffer" ) );
89aecf2014-09-12Per Hedbor  if( THIS->locked )
5e9fc02015-08-18Per Hedbor  push_static_text(" (read only)");
89aecf2014-09-12Per Hedbor  else
5e9fc02015-08-18Per Hedbor  push_static_text("");
89aecf2014-09-12Per Hedbor  f_sprintf(10); } break; case 's':
71050c2014-11-26Henrik Grubbström (Grubba)  bytes = io_len(THIS);
7df96a2015-07-27Henrik Grubbström (Grubba)  THIS->locked_move++;
71050c2014-11-26Henrik Grubbström (Grubba)  push_string( io_read_string(THIS, bytes) ); io_rewind(THIS, bytes);
7df96a2015-07-27Henrik Grubbström (Grubba)  THIS->locked_move--;
89aecf2014-09-12Per Hedbor  break; case 'q':
5e9fc02015-08-18Per Hedbor  push_static_text("%q");
71050c2014-11-26Henrik Grubbström (Grubba)  bytes = io_len(THIS);
7df96a2015-07-27Henrik Grubbström (Grubba)  THIS->locked_move++;
71050c2014-11-26Henrik Grubbström (Grubba)  push_string( io_read_string(THIS, bytes) ); io_rewind(THIS, bytes);
7df96a2015-07-27Henrik Grubbström (Grubba)  THIS->locked_move--;
89aecf2014-09-12Per Hedbor  f_sprintf(2); break; default: push_undefined();
8cccac2014-08-28Per Hedbor  } }
adca9c2014-09-29Stephen R. van den Berg  /*! @decl string(8bit) read_hstring( int(0..) n, void|int offset )
8cccac2014-08-28Per Hedbor  *! *! Identical in functionality to @[read](@[read_number](@[n])) but *! faster. *! *! Read a network byte order number of size n*8 bits, then return the *! indicated number of bytes as a string. *!
adca9c2014-09-29Stephen R. van den Berg  *! @[offset] is substracted from the specified length prior to reading the *! string. Typical usage involves substracting @[n] to account *! for the room used by the size. *!
8cccac2014-08-28Per Hedbor  *! If there is not enough data available return 0. *! *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb). */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) read_hstring( int bytes, void|int offset )
8cccac2014-08-28Per Hedbor  {
0a3c552016-05-09Martin Nilsson  INT64 len;
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8cccac2014-08-28Per Hedbor  struct pike_string *s;
fbc3bf2014-09-08Per Hedbor  ONERROR e;
8cccac2014-08-28Per Hedbor 
ebd1d42014-09-14Per Hedbor  io_rewind_on_error( io, &e ); len = io_read_number( io, bytes );
ebd0042014-09-05Henrik Grubbström (Grubba) 
adca9c2014-09-29Stephen R. van den Berg  if (offset) len -= offset->u.integer;
ebd1d42014-09-14Per Hedbor  if (len < 0) { /* io_avail() in io_read_number() failed. */ CALL_AND_UNSET_ONERROR(e); Pike_sp[-1].u.integer = 0;
ebd0042014-09-05Henrik Grubbström (Grubba)  return; }
ebd1d42014-09-14Per Hedbor  /* NB: We assume that io_avail() in io_read_string() doesn't throw. */
fbc3bf2014-09-08Per Hedbor  s = io_read_string( io, len );
ebd0042014-09-05Henrik Grubbström (Grubba)  if( s ) {
fbc3bf2014-09-08Per Hedbor  io_unset_rewind_on_error( io, &e );
ebd1d42014-09-14Per Hedbor  Pike_sp--;
8cccac2014-08-28Per Hedbor  push_string(s);
ebd0042014-09-05Henrik Grubbström (Grubba)  } else {
ebd1d42014-09-14Per Hedbor  CALL_AND_UNSET_ONERROR(e); Pike_sp[-1].u.integer = 0;
ebd0042014-09-05Henrik Grubbström (Grubba)  }
8cccac2014-08-28Per Hedbor  }
5abd602015-10-25Martin Nilsson  /*! @decl string(8bit) read_cstring(void|int sentinel)
8a3d422014-09-14Stephen R. van den Berg  *! *! Reads a \0 terminated C-string and returns the *! string excluding the terminating \0. *! *! If there is not enough data available return UNDEFINED. *! *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb).
5abd602015-10-25Martin Nilsson  *! *! @param sentinel *! A different character can be used as end sentinel of the string.
e732b22016-10-10Henrik Grubbström (Grubba)  *! *! @seealso *! @[_search()]
8a3d422014-09-14Stephen R. van den Berg  */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) read_cstring(void|int sentinel)
8a3d422014-09-14Stephen R. van den Berg  {
0a3c552016-05-09Martin Nilsson  INT64 len;
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8a3d422014-09-14Stephen R. van den Berg  struct pike_string *s; ONERROR e;
5abd602015-10-25Martin Nilsson  int end = 0; if( sentinel ) end = sentinel->u.integer;
8a3d422014-09-14Stephen R. van den Berg  io_rewind_on_error( io, &e );
bac5392014-09-25Per Hedbor  len = 0; do { /* search the amount of data we know we have for each call to io_avail */ while( io_len(io) ) {
5abd602015-10-25Martin Nilsson  if( io_read_byte_uc(io)==end ) goto found_end;
bac5392014-09-25Per Hedbor  len++; } } while( io_avail( io, 1 ) ); goto fail;
8a3d422014-09-14Stephen R. van den Berg 
5abd602015-10-25Martin Nilsson  found_end:
bac5392014-09-25Per Hedbor  io_rewind( io, len+1 );
8a3d422014-09-14Stephen R. van den Berg  s = io_read_string( io, len ); if( LIKELY(s) ) {
5abd602015-10-25Martin Nilsson  io_read_byte_uc(io); /* consume the terminating byte */
8a3d422014-09-14Stephen R. van den Berg  io_unset_rewind_on_error( io, &e ); push_string(s); } else { fail: CALL_AND_UNSET_ONERROR(e); push_undefined(); } }
e732b22016-10-10Henrik Grubbström (Grubba)  /*! @decl protected int(-1..) _search(int(8bit) character, int|void start) *! *! Search forward from the indicated @[start] position for the specified *! @[character]. *! *! @param character *! Character to search for. *! *! @param start *! Start position relative to the current read position of the buffer. *! *! Negative @[start] values are supported and indicate positions *! prior to the current read position. *! *! @returns *! Returns the first found position of @[character] relative to the *! current read position of the buffer on success, and @[UNDEFINED] *! on not found. The read position is not advanced. *! *! @seealso *! @[read_cstring()], @[search()], @[lfun::_search()] */ PIKEFUN int _search(int(8bit) character, int|void start) flags ID_PROTECTED; { Buffer *io = THIS; unsigned char *buf = io_read_pointer(io); unsigned char *buf_start = buf; unsigned char *buf_end = buf + io_len(io); if (start) { INT_TYPE bytes = start->u.integer; buf_start += bytes; if (bytes >= 0) { if (((size_t)bytes) >= io_len(io)) { push_int(-1); return; } } else if (((size_t)(-bytes)) > io->offset) { bytes = -(ptrdiff_t)io->offset; } buf += bytes; } while (buf < buf_end) { if (UNLIKELY(*buf == character)) { push_int64(buf - io_read_pointer(io)); return; } buf++; } push_int(-1); }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer read_hbuffer( int n ) *! @decl Buffer read_hbuffer( int n, bool copy )
8cccac2014-08-28Per Hedbor  *!
cb65012014-10-01Martin Nilsson  *! Same as @[read_hstring], but returns the result as an Buffer.
8cccac2014-08-28Per Hedbor  *! *! No data is copied unless @[copy] is specified and true, the new *! buffer points into the old one. *! *! @note *! As long as the subbuffer exists no data can be added to the *! main buffer. *! *! Usually this is OK, since it often represents something that *! should be parsed before the next whatever is extracted from *! the buffer, but do take care. *! *! If you need to unlink the new buffer after it has been *! created, call @[trim] in it. */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer read_hbuffer( int bytes, int|void copy )
8cccac2014-08-28Per Hedbor  {
0a3c552016-05-09Martin Nilsson  INT64 len;
8cccac2014-08-28Per Hedbor  int do_copy = 0;
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
fbc3bf2014-09-08Per Hedbor  ONERROR e; io_rewind_on_error( io, &e );
ebd0042014-09-05Henrik Grubbström (Grubba) 
8cccac2014-08-28Per Hedbor  if( copy ) do_copy = copy->u.integer;
7c89442014-09-11Per Hedbor  Pike_sp-=args;
8cccac2014-08-28Per Hedbor 
fbc3bf2014-09-08Per Hedbor  len = io_read_number( io, bytes ); if( len >= 0 && io_avail( io, len ) ) { push_object( io_read_buffer( io, len, do_copy ) ); io_unset_rewind_on_error( io, &e );
ebd0042014-09-05Henrik Grubbström (Grubba)  return; }
fbc3bf2014-09-08Per Hedbor  CALL_AND_UNSET_ONERROR(e); push_int(0);
8cccac2014-08-28Per Hedbor  }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer read_buffer( int n ) *! @decl Buffer read_buffer( int n, bool copy )
8cccac2014-08-28Per Hedbor  *!
cb65012014-10-01Martin Nilsson  *! Same as @[read], but returns the result as an Buffer.
8cccac2014-08-28Per Hedbor  *! *! No data is copied unless @[copy] is specified and true, the new buffer *! points into the old one. *! *! @note *! As long as the subbuffer exists no data can be added to the main buffer. *! *! Usually this is OK, since it often represents something that *! should be parsed before the next whatever is extracted from *! the buffer, but do take care. */
cb65012014-10-01Martin Nilsson  PIKEFUN Buffer read_buffer( int bytes, int|void copy )
8cccac2014-08-28Per Hedbor  { int do_copy = 0; struct object *o; if( copy ) do_copy = copy->u.integer;
7c89442014-09-11Per Hedbor  Pike_sp-=args;
8cccac2014-08-28Per Hedbor  if( (o = io_read_buffer( THIS, bytes, do_copy )) ) push_object(o); else push_int(0); }
cb65012014-10-01Martin Nilsson  /*! @decl Buffer sprintf(strict_sprintf_format format, sprintf_args ... args)
8cccac2014-08-28Per Hedbor  *! *! Appends the output from @[sprintf] at the end of the buffer. *! *! This is somewhat faster than add(sprintf(...)) since no *! intermediate string is created. */
c187512014-10-12Henrik Grubbström (Grubba)  PIKEFUN Buffer sprintf(mixed ... ignored)
8cccac2014-08-28Per Hedbor  rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)),
c187512014-10-12Henrik Grubbström (Grubba)  tAttr("sprintf_args", tMix), tObjIs_BUFFER);
8cccac2014-08-28Per Hedbor  { ONERROR _e; struct string_builder tmp; init_string_builder(&tmp,0); SET_ONERROR(_e, free_string_builder, &tmp);
558e912014-10-05Martin Nilsson  low_f_sprintf(args, &tmp);
8cccac2014-08-28Per Hedbor  if( tmp.s->size_shift )
cb65012014-10-01Martin Nilsson  Pike_error("Buffer only handles 8bit data\n");
7c34772014-09-11Per Hedbor  io_append( THIS, tmp.s->str, tmp.s->len );
8cccac2014-08-28Per Hedbor  pop_n_elems(args); CALL_AND_UNSET_ONERROR(_e);
fbc3bf2014-09-08Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  } /*! @decl array sscanf(string(8bit) format) *! *! Reads data from the beginning of the buffer to match the *! specifed format, then return an array with the matches. *! *! The non-matching data will be left in the buffer. *! *! See @[array_sscanf] for more information. */ PIKEFUN array sscanf( string format ) { INT32 i; ptrdiff_t num_used; struct svalue *start = Pike_sp;
317fc32014-09-02Per Hedbor  retry:
8cccac2014-08-28Per Hedbor  i = low_sscanf_pcharp( MKPCHARP(io_read_pointer(THIS), 0), io_len(THIS), MKPCHARP(format->str,format->size_shift), format->len,
558e912014-10-05Martin Nilsson  &num_used);
8cccac2014-08-28Per Hedbor  if( !num_used ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8cccac2014-08-28Per Hedbor  pop_n_elems(Pike_sp-start); push_int(0); } else { io_consume( THIS, num_used ); f_aggregate(Pike_sp-start); } }
8f08202014-08-28Per Hedbor  /*! @decl mixed read_json(int|void require_whitespace_separator) *! *! Read a single JSON expression from the buffer and return it.
317fc32014-09-02Per Hedbor  *!
8f08202014-08-28Per Hedbor  *! If @[require_whitespace_separator] is true there must be a whitespace *! after each json value (as an example, newline or space). *! *! The JSON is assumed to be utf-8 encoded. *! *! @returns *! UNDEFINED if no data is available to read. *! The read value otherwise. *! *! @note *! Unless whitespaces are required this function only really work correctly *! with objects, arrays and strings. *! *! There is really no way to see where one value starts and the other ends *! for most other cases */ PIKEFUN mixed read_json(int|void require_whitespace) { int stop, whites = 0; static ptrdiff_t(*parse_json_pcharp)(PCHARP,size_t,int,char**); char *err = NULL; if( require_whitespace ) whites = require_whitespace->u.integer;
89aecf2014-09-12Per Hedbor  Pike_sp-=args;
8f08202014-08-28Per Hedbor  if( !parse_json_pcharp ) parse_json_pcharp = PIKE_MODULE_IMPORT(Standards.JSON, parse_json_pcharp );
317fc32014-09-02Per Hedbor  retry:
8f08202014-08-28Per Hedbor  stop = parse_json_pcharp( MKPCHARP(io_read_pointer(THIS),0), io_len(THIS), 1|8, &err ); /* json_utf8 */ if( stop < 0 ) { if( -stop == (ptrdiff_t)io_len(THIS) || (err && !strncmp(err,"Unterminated",12))) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8f08202014-08-28Per Hedbor  push_undefined(); } else { /* FIXME: Use real json error? */ if( err ) Pike_error("Syntax error in json at offset %d: %s\n", -stop, err ); else Pike_error("Syntax error in json at offset %d\n", -stop ); } } else { if( whites && (io_is_whitespace(THIS,stop)<=0 && io_is_whitespace(THIS,stop-1)<=0)) { if( stop == (ptrdiff_t)io_len(THIS) ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8f08202014-08-28Per Hedbor  pop_stack(); push_undefined(); } else Pike_error("Missing whitespace between json values at offset %d\n", stop ); } else { if( whites ) while( io_is_whitespace( THIS, stop ) ) stop++; io_consume( THIS, stop ); } } }
8cccac2014-08-28Per Hedbor  /*! @decl mixed match(string(8bit) format) *! *! Reads data from the beginning of the buffer to match the *! specifed format, then return the match. *! *! The non-matching data will be left in the buffer. *! *! This function is very similar to @[sscanf], but the *! result is the sum of the matches. Most useful to match *! a single value. *! *! @example *! @code *! // get the next whitespace separated word from the buffer.
89aecf2014-09-12Per Hedbor  *! buffer->match("%*[ \t\r\n]%[^ \t\r\n]");
8cccac2014-08-28Per Hedbor  *! @endcode */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit)|int|float|array match( string format )
8cccac2014-08-28Per Hedbor  { INT32 i; ptrdiff_t num_used; struct svalue *start = Pike_sp;
317fc32014-09-02Per Hedbor  retry:
8cccac2014-08-28Per Hedbor  i = low_sscanf_pcharp( MKPCHARP(io_read_pointer(THIS), 0), io_len(THIS), MKPCHARP(format->str,format->size_shift), format->len,
558e912014-10-05Martin Nilsson  &num_used);
8cccac2014-08-28Per Hedbor  if( !num_used ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8cccac2014-08-28Per Hedbor  pop_n_elems(Pike_sp-start); push_int(0); } else { io_consume( THIS, num_used );
89aecf2014-09-12Per Hedbor  if( Pike_sp-start > 1 )
8cccac2014-08-28Per Hedbor  f_add(Pike_sp-start); } } /*! @decl void clear() *! *! Clear the buffer. */ PIKEFUN void clear( ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8cccac2014-08-28Per Hedbor  io->offset = io->len = 0; }
9171842015-07-13Per Hedbor  /*! @decl void set_max_waste(float factor) *! *! Configure how much free space should be allowed, at most, as a *! factor of the current buffer size. *! *! The default is 0.5, leaving at most half the buffer as waste. *! */ PIKEFUN void set_max_waste(float howmuch) { Buffer *io = THIS; io->max_waste = howmuch; io_add_space( io, 0, 1 ); io_consume( io, 0 ); }
8cccac2014-08-28Per Hedbor  /*! @decl void trim() *! *! Frees unused memory. *! *! Note that calling this function excessively will slow things *! down, since the data often has to be copied. *! *! @note *! This function could possibly throw an out-of-memory error *! if the realloc fails to find a new (smaller) memory area. */ PIKEFUN void trim( ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
87cfd22015-05-15Tobias S. Josefowitz 
8cccac2014-08-28Per Hedbor  io_add_space( io, 0, 1 );
9171842015-07-13Per Hedbor  io_trim(io);
8cccac2014-08-28Per Hedbor  } /*! @decl int(0..)|int(-1..-1) consume( int(0..) n ) *! *! Discard the first @[n] bytes from the buffer
fbc3bf2014-09-08Per Hedbor  *! *! Returns -1 on error and the amount of space still left otherwise.
8cccac2014-08-28Per Hedbor  */ PIKEFUN int(-1..) consume( int n ) {
89aecf2014-09-12Per Hedbor  Pike_sp--;
ebd1d42014-09-14Per Hedbor  if( !io_avail( THIS, n ) )
8cccac2014-08-28Per Hedbor  push_int(-1); else push_int64( io_consume( THIS, n ) ); }
c34be02015-11-21Arne Goedeke  /*! @decl int(0..)|int(-1..-1) truncate( int(0..) n ) *! *! Truncates the buffer to a length of @[n] bytes. *! *! Returns -1 on error and the number of bytes removed otherwise. */ PIKEFUN int(-1..) truncate( int(0..) n ) { Buffer *io = THIS; ptrdiff_t diff = io_len(io) - n; Pike_sp--; if( diff < 0 || io_len(io) < (size_t)diff ) push_int(-1); else { io->len -= diff; push_int64( diff ); } }
8cccac2014-08-28Per Hedbor  /*! @decl int(0..)|int(-1..-1) unread( int(0..) n ) *! *! Rewind the buffer @[n] bytes. *! *! @returns *! *! This function returns how many more bytes of buffer is *! available to rewind, or -1 on error. *! *! @note *! *! Unless you add new data to the buffer using any of the add *! functions you can always rewind. *!
b064882014-09-11Stephen R. van den Berg  *! You can call @[unread(0)] to see how much.
8cccac2014-08-28Per Hedbor  */
9629ad2014-09-01Per Hedbor  PIKEFUN int(-1..) unread( int bytes )
8cccac2014-08-28Per Hedbor  {
89aecf2014-09-12Per Hedbor  Pike_sp--;
ebd1d42014-09-14Per Hedbor  push_int64( io_rewind( THIS, bytes ) );
8cccac2014-08-28Per Hedbor  } /*! @decl string(8bit) read( int n ) *! *! Read @[bytes] bytes of data from the buffer. *! *! If there is not enough data available this returns 0.
f744bf2014-09-15Henrik Grubbström (Grubba)  *! *! @seealso *! @[try_read()]
8cccac2014-08-28Per Hedbor  */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) read( int bytes )
8cccac2014-08-28Per Hedbor  {
317fc32014-09-02Per Hedbor  struct pike_string *s;
89aecf2014-09-12Per Hedbor  Pike_sp--;
317fc32014-09-02Per Hedbor  s = io_read_string(THIS, bytes );
8cccac2014-08-28Per Hedbor  if( s )
89aecf2014-09-12Per Hedbor  push_string( s ); else push_undefined();
8cccac2014-08-28Per Hedbor  } /*! @decl string(8bit) read( ) *! *! Read all data from the buffer. *! *! If there is not enough data available this returns 0. *! *! This is basically equivalent to (string)buffer, but it also *! removes the data from the buffer.
f744bf2014-09-15Henrik Grubbström (Grubba)  *! *! @seealso *! @[try_read()]
8cccac2014-08-28Per Hedbor  */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) read()
8cccac2014-08-28Per Hedbor  {
8cfdd82014-09-15Per Hedbor  push_string( io_read_string(THIS, io_len(THIS)) );
f744bf2014-09-15Henrik Grubbström (Grubba)  } /*! @decl string(8bit) try_read(int len) *! *! Attempt to read some data from the buffer. *! *! @param len *! Read at most @[len] bytes from the buffer. *! *! @returns *! If the buffer contains less than @[len] bytes *! of data, the entire buffer contents are returned. *! Otherwise the first @[len] bytes are returned. *! *! @seealso *! @[read()] */
ecee5c2016-05-27Per Hedbor  PIKEFUN string(8bit) try_read( int bytes )
f744bf2014-09-15Henrik Grubbström (Grubba)  {
cb65012014-10-01Martin Nilsson  Buffer *this = THIS;
f744bf2014-09-15Henrik Grubbström (Grubba)  struct pike_string *s; Pike_sp--;
4015132014-09-15Per Hedbor  /* Hm. signed/unsigned comparisons abound. */
e555b02014-09-15Per Hedbor  if( bytes > 0 && (size_t)bytes > io_len(this) )
4015132014-09-15Per Hedbor  bytes = io_len(this); push_string( io_read_string(this, bytes ) );
8cccac2014-08-28Per Hedbor  }
c5e3e52014-09-10Per Hedbor  /*! @decl int(8bit) read_int8() */ PIKEFUN int(8bit) read_int8( ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
c5e3e52014-09-10Per Hedbor  if( LIKELY(io_avail( io, 1 )) ) push_int( io_read_byte_uc(io) ); else push_int(-1); } /*! @decl int(16bit) read_int16() */ PIKEFUN int(0..65535) read_int16( ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
c5e3e52014-09-10Per Hedbor  if( LIKELY(io_avail( io, 2 )) ) push_int( io_read_number_uc(io,2) ); else push_int(-1); } /*! @decl int(24bit) read_int24() */ PIKEFUN int(0..16777215) read_int24( ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
c5e3e52014-09-10Per Hedbor  if( LIKELY(io_avail( io, 3 )) ) push_int( io_read_number_uc(io,3) ); else push_int(-1); }
0455182014-09-11Arne Goedeke  /*! @decl int(32bit) read_int32()
c5e3e52014-09-10Per Hedbor  */
0455182014-09-11Arne Goedeke  PIKEFUN int(0..4294967295) read_int32( )
c5e3e52014-09-10Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
c5e3e52014-09-10Per Hedbor  if( LIKELY(io_avail( io, 4 )) )
130baa2014-10-03Per Hedbor  {
c5e3e52014-09-10Per Hedbor  push_int( io_read_number_uc(io,4) );
130baa2014-10-03Per Hedbor #if SIZEOF_INT_TYPE < 5 if( UNLIKELY(Pike_sp[-1].u.integer < 0) ) { io_rewind( io, 4 ); pop_stack(); push_object( io_read_bignum(io, 4) ); } #endif }
c5e3e52014-09-10Per Hedbor  else push_int(-1); }
74e52c2014-08-28Per Hedbor  /*! @decl int read_int( int n )
8cccac2014-08-28Per Hedbor  *!
fbc3bf2014-09-08Per Hedbor  *! Read a network byte order unsigned number of size n*8 bits, then
8cccac2014-08-28Per Hedbor  *! return it. *! *! Will return -1 if there is not enough buffer space available *! unless error mode is set to throw errors. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) read_int( int len )
8cccac2014-08-28Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
8cccac2014-08-28Per Hedbor  struct object *o;
89aecf2014-09-12Per Hedbor  Pike_sp--;
8cccac2014-08-28Per Hedbor  if( len < SIZEOF_INT_TYPE-1 ) /* will for sure fit. */ { push_int( io_read_number( io, len ) ); return; } if( (o = io_read_bignum(io, len )) ) { push_object(o); reduce_stack_top_bignum(); return; } push_int(-1); }
3a3c822014-09-25Per Hedbor  /*! @decl int read_hint( int n ) *! *! Read a network byte order unsigned number of size n*8 bits, then *! read another network byte order number of the size indicated by *! the first size. *! *! Will return -1 if there is not enough buffer space available *! unless error mode is set to throw errors. */ PIKEFUN int(0..) read_hint( int size_len ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
3a3c822014-09-25Per Hedbor  ONERROR e; INT_TYPE len; struct object *o; io_rewind_on_error( io, &e ); len = io_read_number( io, size_len ); if( len >= 0 ) { if( len < SIZEOF_INT_TYPE ) { if( (Pike_sp[-1].u.integer = io_read_number( io, len )) == -1 ) goto neg_one; } else if( (o = io_read_bignum( io, len )) ) { Pike_sp--; push_object(o); reduce_stack_top_bignum(); } else goto neg_one; io_unset_rewind_on_error( io, &e ); return; } neg_one: Pike_sp[-1].u.integer = -1; CALL_AND_UNSET_ONERROR(e); }
fbc3bf2014-09-08Per Hedbor  /*! @decl array(int) read_ints( int n, int width ) *! *! Read a list of @[n] network byte order unsigned numbers each of *! size @[width]*8 bits, then return it. *! *! Will return 0 if there is not enough buffer space available *! unless error mode is set to throw errors. */ PIKEFUN array(int(0..)) read_ints( int num, int len ) {
cb65012014-10-01Martin Nilsson  Buffer *io = THIS;
fbc3bf2014-09-08Per Hedbor  INT_TYPE i; struct object *o; struct array *a;
89aecf2014-09-12Per Hedbor  Pike_sp-=2;
fbc3bf2014-09-08Per Hedbor 
ebd1d42014-09-14Per Hedbor  if( !io_avail_mul( io, num, len ) )
fbc3bf2014-09-08Per Hedbor  { push_int(0); return; } if( len < SIZEOF_INT_TYPE-1 ) /* will for sure fit. */ { push_array(a = allocate_array(num)); for( i=0;i<num;i++ ) a->item[i].u.integer = io_read_number_uc( io, len ); return; } for( i=0; i<num; i++ ) { push_object(io_read_bignum( io, len )); reduce_stack_top_bignum(); } f_aggregate(num); }
6d47962014-09-01Per Hedbor /*! @decl string _encode() *! @decl void _decode(string x) *!
cb65012014-10-01Martin Nilsson  *! Encode and decode Stdio.Buffer objects.
6d47962014-09-01Per Hedbor  *! Only the buffer data is kept, no other state is saved. */ PIKEFUN string _encode() {
fbc3bf2014-09-08Per Hedbor  push_string(io_read_string(THIS, io_len(THIS)));
6d47962014-09-01Per Hedbor  }
ecee5c2016-05-27Per Hedbor  PIKEFUN void _decode(string(8bit) x)
6d47962014-09-01Per Hedbor  {
cb65012014-10-01Martin Nilsson  Buffer *this = THIS;
6d47962014-09-01Per Hedbor  if( this->buffer ) Pike_error("Can not initialize twice.\n"); if( x->size_shift ) Pike_error("Can not handle non-8bit data.\n"); this->buffer = (unsigned char*)x->str; this->len = x->len; this->malloced = 0; this->str = x;
929b282014-09-18Henrik Grubbström (Grubba)  add_ref(x);
6d47962014-09-01Per Hedbor  }
8b141e2014-09-01Per Hedbor  /*! @decl void read_only()
8cccac2014-08-28Per Hedbor  *!
8b141e2014-09-01Per Hedbor  *! Make the buffer permanently read only. *! @note *! You can use lock() to do this temporarily. */ PIKEFUN void read_only() { io_lock( THIS ); }
aee7642014-09-25Per Hedbor 
cb65012014-10-01Martin Nilsson  static struct object* io_create_rewind_key( Buffer *io, int how );
aee7642014-09-25Per Hedbor 
bac5392014-09-25Per Hedbor  /*! @decl RewindKey rewind_on_error() *! @decl RewindKey rewind_key()
aee7642014-09-25Per Hedbor  *!
bac5392014-09-25Per Hedbor  *! These functions are very similar. The @[rewind_on_error] edition *! will create an object that, when it goes out of scope without *! having been destructed explicitly, will cause the buffer to *! rewind to the location it had when this function is called.
aee7642014-09-25Per Hedbor  *!
bac5392014-09-25Per Hedbor  *! This will happen if you throw an error @i{or@} otherwise let the
aee7642014-09-25Per Hedbor  *! object fall out of scope. *!
bac5392014-09-25Per Hedbor  *! Use @[destruct(RewindKey)] or @[RewindKey.release] to stop the *! buffer from being rewound. *! *! The second version (@[rewind_key]) requires you to explicitly *! call @[RewindKey.rewind] to do the rewind. *!
aee7642014-09-25Per Hedbor  *! Take some care with these objects, if you create multiple ones *! at once the results might be somewhat confusing if you do not *! release them in the reverse order they were created in (then *! again, you almost certainly really only need one) *!
bac5392014-09-25Per Hedbor  *! You can call @[RewindKey.update] in the generated object to *! change where it will be rewound to.
aee7642014-09-25Per Hedbor  *!
bac5392014-09-25Per Hedbor  *! The typical use-case of this functionality is when parsing a
f8c6fc2014-10-19Henrik Grubbström (Grubba)  *! packet protocol with variable length packets where the length is
bac5392014-09-25Per Hedbor  *! not immediately known. It saves you from keeping track of how *! much to rewind if you had not actually gotten the whole packet *! yet.
aee7642014-09-25Per Hedbor  *! *! @example *! @code
cb65012014-10-01Martin Nilsson  *! void parse_packet( Stdio.Buffer b )
aee7642014-09-25Per Hedbor  *! {
cb65012014-10-01Martin Nilsson  *! Stdio.Buffer.RewindKey rewind = b->rewind_on_error();
aee7642014-09-25Per Hedbor  *! b->set_error_mode(1); *! *! switch( b->read_int8() ) // packet type *! { *! case DATA: *! int channel = b->read_int8();
cb65012014-10-01Martin Nilsson  *! Stdio.Buffer data = b->read_hbuffer( 4 );
aee7642014-09-25Per Hedbor  *! // we have read the whole packet, so no longer rewind on error. *! rewind->release();
f8c6fc2014-10-19Henrik Grubbström (Grubba)  *! return handle_data_packet( channel, data );
aee7642014-09-25Per Hedbor  *! } *! } *! @endcode
bac5392014-09-25Per Hedbor  *! @note *! Just calling @[rewind_on_error] without assigning the return *! value to something will not do anything. You need to keep the *! object around while the rewind-to position is still valid. *! *! Keeping the object around forbids the buffer from moving data *! inside itself, this means that it can only grow. So do not keep *! the rewind key when it is not needed.
aee7642014-09-25Per Hedbor  */
0c43c62014-11-20Martin Nilsson  PIKEFUN object(Buffer.RewindKey) rewind_on_error()
aee7642014-09-25Per Hedbor  {
bac5392014-09-25Per Hedbor  push_object( io_create_rewind_key( THIS, 1 ) ); }
0c43c62014-11-20Martin Nilsson  PIKEFUN object(Buffer.RewindKey) rewind_key()
bac5392014-09-25Per Hedbor  { push_object( io_create_rewind_key( THIS, 0 ) );
aee7642014-09-25Per Hedbor  }
8b141e2014-09-01Per Hedbor  /*! @decl void create( int|void len ) *! @decl void create( string(8bit) contents ) *! @decl void create( System.Memory|String.Buffer contents ) *! *! If passed an integer or no argument, create a buffer of that
317fc32014-09-02Per Hedbor  *! size, or if no argument is given, 226 bytes.
8b141e2014-09-01Per Hedbor  *! *! If @[contents] are specified a new buffer with the contents of *! the given string/System.Memory or String.Buffer will be created.
8cccac2014-08-28Per Hedbor  *! *! @note
8b141e2014-09-01Per Hedbor  *! In the @[String.Buffer] case the data has to be copied unless *! there is only one reference to the String.Buffer object, since
cb65012014-10-01Martin Nilsson  *! modifications of the String.Buffer would cause the Buffer to
8b141e2014-09-01Per Hedbor  *! point into invalid memory. *! *! In all other cases this will not copy the string data, instead *! data will be read from the source until it needs to be modified, *! so the buffer creation is fast regardless of the length of the
8cccac2014-08-28Per Hedbor  *! string.
8b141e2014-09-01Per Hedbor  *! *! However, as an example, if the buffer is created with a 100Gb *! @[System.Memory] mmap:ed file as the @[contents] and you later on *! try to modify the buffer using one of the @[add] functions (or *! @[sprintf] and similar) the old contents @b{will@} be copied. *! *! You can use @[read_only()] to avoid accidents.
8cccac2014-08-28Per Hedbor  */
f3ed292014-09-11Per Hedbor  PIKEFUN void create( int|void|string|object|array x )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; {
cb65012014-10-01Martin Nilsson  Buffer *this = THIS;
8cccac2014-08-28Per Hedbor  if( this->buffer ) Pike_error("Can not initialize twice.\n");
e2e5382015-04-25Henrik Grubbström (Grubba)  if( !x )
f3ed292014-09-11Per Hedbor  { this->buffer = xalloc(256-32); this->allocated = 256-32; this->malloced = 1; } else if( TYPEOF(*x) == PIKE_T_INT ) { INT_TYPE len = x->u.integer; if( len <= 0 )
fbc3bf2014-09-08Per Hedbor  this->buffer = xalloc(1);
f3ed292014-09-11Per Hedbor  else
fbc3bf2014-09-08Per Hedbor  this->buffer = xalloc(len);
d304612015-04-07Henrik Grubbström (Grubba)  this->allocated = MAXIMUM(len,1);
f3ed292014-09-11Per Hedbor  this->malloced = 1; } else io_append_svalue( THIS, x );
8cccac2014-08-28Per Hedbor  } INIT {
cb65012014-10-01Martin Nilsson  Buffer *this = THIS; memset( this, 0, sizeof(Buffer));
9171842015-07-13Per Hedbor  this->max_waste = 0.615;
317fc32014-09-02Per Hedbor  this->this = Pike_fp->current_object;
8cccac2014-08-28Per Hedbor  } EXIT {
cb65012014-10-01Martin Nilsson  Buffer *this = THIS;
50c7192014-09-10Per Hedbor  io_unlink_external_storage( this );
9629ad2014-09-01Per Hedbor  if( this->error_mode ) free_program( this->error_mode );
8cccac2014-08-28Per Hedbor  if( this->malloced ) free( this->buffer ); }
aee7642014-09-25Per Hedbor 
bac5392014-09-25Per Hedbor /*! @class RewindKey
aee7642014-09-25Per Hedbor  *!
cb65012014-10-01Martin Nilsson  *! The return value of @[Buffer.rewind_on_error()] and *! @[Buffer.rewind_key()]
aee7642014-09-25Per Hedbor  *!
bac5392014-09-25Per Hedbor  *! This object will cause the buffer to unwind to the position it was *! at when the object was created either when it is released (when it *! falls out of scope, explicit destruct does not count) or when *! @[rewind] is called, depending on which function was used to *! create it.
aee7642014-09-25Per Hedbor  */
bac5392014-09-25Per Hedbor  PIKECLASS RewindKey
aee7642014-09-25Per Hedbor  flags PROGRAM_DESTRUCT_IMMEDIATE; {
cb65012014-10-01Martin Nilsson  CVAR Buffer *io;
aee7642014-09-25Per Hedbor  CVAR struct object *obj; CVAR size_t rewind_to;
bac5392014-09-25Per Hedbor  CVAR int auto_mode;
aee7642014-09-25Per Hedbor  /*! @decl void release()
bac5392014-09-25Per Hedbor  *! Do not rewind if the object is released. *! @note *! This is equivalent to calling destruct() on the object
aee7642014-09-25Per Hedbor  */ PIKEFUN void release() { destruct_object(Pike_fp->current_object, DESTRUCT_EXPLICIT); } /*! @decl void update() *! *! Update the location the buffer will be rewound to to the current *! position of the buffer. */ PIKEFUN void update() { if( THIS->obj->prog && THIS->io ) THIS->rewind_to = THIS->io->offset; } EXIT { if( THIS->io && THIS->obj->prog ) THIS->io->locked_move--; free_object( THIS->obj ); } PIKEFUN void destroy( int reason ) flags ID_PRIVATE; {
bac5392014-09-25Per Hedbor  if( reason > 1 && THIS->auto_mode ) /* no refs or gc */
aee7642014-09-25Per Hedbor  { if( THIS->io && THIS->obj->prog ) THIS->io->offset = THIS->rewind_to; } }
a4a6482014-09-25Tobias S. Josefowitz  /*! @decl void rewind() *! Rewinds the buffer explicitly. *! @note
bac5392014-09-25Per Hedbor  *! Destructs this @[RewindKey]
a4a6482014-09-25Tobias S. Josefowitz  */ PIKEFUN void rewind() {
bac5392014-09-25Per Hedbor  THIS->auto_mode = 1;
a4a6482014-09-25Tobias S. Josefowitz  destruct_object(Pike_fp->current_object, DESTRUCT_GC); }
aee7642014-09-25Per Hedbor  PIKEFUN void create() flags ID_PRIVATE; {
c7607f2014-10-05Henrik Grubbström (Grubba)  /* FIXME: The following zeroing isn't safe! */
aee7642014-09-25Per Hedbor  THIS->obj = 0; THIS->io = 0; Pike_error("Not supported\n"); } }
774d642016-05-23Henrik Grubbström (Grubba)  /*! @endclass RewindKey */
aee7642014-09-25Per Hedbor 
774d642016-05-23Henrik Grubbström (Grubba)  static struct object* io_create_rewind_key( Buffer *io, int auto_mode ) { struct object *o = fast_clone_object( Buffer_RewindKey_program ); struct Buffer_RewindKey_struct *s = (void*)o->storage; add_ref(io->this); s->obj = io->this; s->rewind_to = io->offset; s->io = io; s->auto_mode = auto_mode; io->locked_move++; return o; }
aee7642014-09-25Per Hedbor 
8cccac2014-08-28Per Hedbor }
774d642016-05-23Henrik Grubbström (Grubba) /*! @endclass Buffer
aee7642014-09-25Per Hedbor  */
774d642016-05-23Henrik Grubbström (Grubba) /*! @endmodule Stdio
aee7642014-09-25Per Hedbor  */
8cccac2014-08-28Per Hedbor void init_stdio_buffer(void) { INIT
10150d2014-09-01Per Hedbor  start_new_program(); low_inherit(generic_error_program,0,0,0,0,0); add_integer_constant( "buffer_error", 1, 0 ); buffer_error_program = end_program();
8cccac2014-08-28Per Hedbor } void exit_stdio_buffer(void) {
10150d2014-09-01Per Hedbor  free_program( buffer_error_program );
8cccac2014-08-28Per Hedbor  EXIT }