Пример #1
0
/**
 * Handle a call to recv() made by JavaScript.
 *
 * recv expects 2 parameters:
 *   0: The socket file descriptor to recv from.
 *   1: The size of the buffer to pass to recv.
 * on success, send returns a result in |output|:
 *   0: "recv"
 *   1: The number of bytes received.
 *   2: The data received.
 * on failure, recv returns an error string in |out_error|.
 */
int HandleRecv(struct PP_Var params,
               struct PP_Var* output,
               const char** out_error) {
  CHECK_PARAM_COUNT(recv, 2);
  PARAM_INT(0, sock);
  PARAM_INT(1, buffersize);

  if (buffersize < 0 || buffersize > 65 * 1024) {
    *out_error =
        PrintfToNewString("recv buffersize must be between 0 and 65k.");
    return 1;
  }

  char* buffer = alloca(buffersize);
  memset(buffer, 0, buffersize);
  int result = (int32_t)recv(sock, buffer, buffersize, 0);
  if (result <= 0) {
    *out_error = PrintfToNewString("recv failed: %s", strerror(errno));
    return 1;
  }

  CREATE_RESPONSE(recv);
  RESPONSE_INT(result);
  RESPONSE_STRING(buffer);
  return 0;
}
Пример #2
0
/**
 * Handle a call to fopen() made by JavaScript.
 *
 * fopen expects 2 parameters:
 *   0: the path of the file to open
 *   1: the mode string
 * on success, fopen returns a result in |output|:
 *   0: "fopen"
 *   1: the filename opened
 *   2: the file index
 * on failure, fopen returns an error string in |out_error|.
 */
int HandleFopen(struct PP_Var params,
                struct PP_Var* output,
                const char** out_error) {
  CHECK_PARAM_COUNT(fopen, 2);
  PARAM_STRING(0, filename);
  PARAM_STRING(1, mode);

  FILE* file = fopen(filename, mode);

  if (!file) {
    *out_error = PrintfToNewString("fopen returned a NULL FILE*");
    return 1;
  }

  int file_index = AddFileToMap(file);
  if (file_index == -1) {
    *out_error = PrintfToNewString("Example only allows %d open file handles",
                                   MAX_OPEN_FILES);
    return 1;
  }

  CREATE_RESPONSE(fopen);
  RESPONSE_STRING(filename);
  RESPONSE_INT(file_index);
  return 0;
}
Пример #3
0
/**
 * Handle a call to opendir() made by JavaScript.
 *
 * opendir expects 1 parameter:
 *   0: The name of the directory
 * on success, opendir returns a result in |output|:
 *   0: "opendir"
 *   1: the directory name
 *   2: the index of the directory
 * on failure, opendir returns an error string in |out_error|.
 */
int HandleOpendir(struct PP_Var params,
                  struct PP_Var* output,
                  const char** out_error) {
#if defined(WIN32)
  *out_error = PrintfToNewString("Win32 does not support opendir");
  return 1;
#else
  CHECK_PARAM_COUNT(opendir, 1);
  PARAM_STRING(0, dirname);

  DIR* dir = opendir(dirname);

  if (!dir) {
    *out_error = PrintfToNewString("opendir returned a NULL DIR*");
    return 1;
  }

  int dir_index = AddDirToMap(dir);
  if (dir_index == -1) {
    *out_error = PrintfToNewString("Example only allows %d open dir handles",
                                   MAX_OPEN_DIRS);
    return 1;
  }

  CREATE_RESPONSE(opendir);
  RESPONSE_STRING(dirname);
  RESPONSE_INT(dir_index);
  return 0;
#endif
}
Пример #4
0
/**
 * Handle a call to gethostbyname() made by JavaScript.
 *
 * gethostbyname expects 1 parameter:
 *   0: The name of the host to look up.
 * on success, gethostbyname returns a result in |output|:
 *   0: "gethostbyname"
 *   1: Host name
 *   2: Address type (either "AF_INET" or "AF_INET6")
 *   3: The first address.
 *   4+ The second, third, etc. addresses.
 * on failure, gethostbyname returns an error string in |out_error|.
 */
int HandleGethostbyname(struct PP_Var params,
                        struct PP_Var* output,
                        const char** out_error) {
  CHECK_PARAM_COUNT(gethostbyname, 1);
  PARAM_STRING(0, name);

  struct hostent* info = gethostbyname(name);
  if (!info) {
    *out_error = PrintfToNewString("gethostbyname failed, error is \"%s\"",
                                   hstrerror(h_errno));
    return 1;
  }

  CREATE_RESPONSE(gethostbyname);
  RESPONSE_STRING(info->h_name);
  RESPONSE_STRING(info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6");

  struct in_addr** addr_list = (struct in_addr**)info->h_addr_list;
  int i;
  for (i = 0; addr_list[i] != NULL; i++) {
    if (info->h_addrtype == AF_INET) {
      RESPONSE_STRING(inet_ntoa(*addr_list[i]));
    } else {  // IPv6
      char addr_str[INET6_ADDRSTRLEN];
      inet_ntop(AF_INET6, addr_list[i], addr_str, sizeof(addr_str));
      RESPONSE_STRING(addr_str);
    }
  }
  return 0;
}
Пример #5
0
/**
 * Handle a call to fseek() made by JavaScript.
 *
 * fseek expects 3 parameters:
 *   0: The index of the file (which is mapped to a FILE*)
 *   1: The offset to seek to
 *   2: An integer representing the whence parameter of standard fseek.
 *      whence = 0: seek from the beginning of the file
 *      whence = 1: seek from the current file position
 *      whence = 2: seek from the end of the file
 * on success, fseek returns a result in |output|:
 *   0: "fseek"
 *   1: the file index
 *   2: The new file position
 * on failure, fseek returns an error string in |out_error|.
 */
int HandleFseek(struct PP_Var params,
                struct PP_Var* output,
                const char** out_error) {
  CHECK_PARAM_COUNT(fseek, 3);
  PARAM_FILE(0, file);
  PARAM_INT(1, offset);
  PARAM_INT(2, whence);

  int result = fseek(file, offset, whence);
  if (result) {
    *out_error = PrintfToNewString("fseek returned error %d", result);
    return 1;
  }

  offset = (int32_t)ftell(file);
  if (offset < 0) {
    *out_error = PrintfToNewString(
        "fseek succeeded, but ftell returned error %d", offset);
    return 1;
  }

  CREATE_RESPONSE(fseek);
  RESPONSE_INT(file_index);
  RESPONSE_INT(offset);
  return 0;
}
Пример #6
0
static int tty_setWinTitle_25(struct pvm_object me , struct data_area_4_thread *tc )
{
    DEBUG_INFO;
    struct data_area_4_tty      *da = pvm_data_area( me, tty );


    int n_param = POP_ISTACK;
    CHECK_PARAM_COUNT(n_param, 1);

    struct pvm_object _text = POP_ARG;
    ASSERT_STRING(_text);

    int len = pvm_get_str_len( _text );
    const char * data = (const char *)pvm_get_str_data(_text);

    if( len > PVM_MAX_TTY_TITLE-1 ) len = PVM_MAX_TTY_TITLE-1 ;
    strlcpy( da->title, data, len+1 );
    //buf[len] = 0;

    SYS_FREE_O(_text);

    w_set_title( &(da->w), da->w.title );

    SYSCALL_RETURN_NOTHING;
}
Пример #7
0
/**
 * Handle a call to fflush() made by JavaScript.
 *
 * fflush expects 1 parameters:
 *   0: The index of the file (which is mapped to a FILE*)
 * on success, fflush returns a result in |output|:
 *   0: "fflush"
 *   1: the file index
 * on failure, fflush returns an error string in |out_error|.
 */
int HandleFflush(struct PP_Var params,
                 struct PP_Var* output,
                 const char** out_error) {
  CHECK_PARAM_COUNT(fflush, 1);
  PARAM_FILE(0, file);

  fflush(file);

  CREATE_RESPONSE(fflush);
  RESPONSE_INT(file_index);
  return 0;
}
Пример #8
0
int Handle_iguana(struct PP_Var params,struct PP_Var *output,const char **out_error)
{
    char *iguana_JSON(char *);
    char *retstr;
    PostMessage("inside Handle_iguana\n");
    CHECK_PARAM_COUNT(iguana, 1);
    PARAM_STRING(0,jsonstr);
    retstr = iguana_JSON(jsonstr);
    CREATE_RESPONSE(iguana);
    RESPONSE_STRING(retstr);
    return 0;
}
Пример #9
0
/**
 * Handle a call to getaddrinfo() made by JavaScript.
 *
 * getaddrinfo expects 1 parameter:
 *   0: The name of the host to look up.
 * on success, getaddrinfo returns a result in |output|:
 *   0: "getaddrinfo"
 *   1: The canonical name
 *   2*n+2: Host name
 *   2*n+3: Address type (either "AF_INET" or "AF_INET6")
 * on failure, getaddrinfo returns an error string in |out_error|.
 */
int HandleGetaddrinfo(struct PP_Var params,
                      struct PP_Var* output,
                      const char** out_error) {
  CHECK_PARAM_COUNT(getaddrinfo, 2);
  PARAM_STRING(0, name);
  PARAM_STRING(1, family);

  struct addrinfo hints;
  memset(&hints, 0, sizeof(hints));
  hints.ai_flags = AI_CANONNAME;
  if (!strcmp(family, "AF_INET"))
    hints.ai_family = AF_INET;
  else if (!strcmp(family, "AF_INET6"))
    hints.ai_family = AF_INET6;
  else if (!strcmp(family, "AF_UNSPEC"))
    hints.ai_family = AF_UNSPEC;
  else {
    *out_error = PrintfToNewString("getaddrinfo uknown family: %s", family);
    return 1;
  }

  struct addrinfo* ai;
  int rtn = getaddrinfo(name, NULL, &hints, &ai);
  if (rtn != 0) {
    *out_error = PrintfToNewString("getaddrinfo failed, error is \"%s\"",
                                   gai_strerror(rtn));
    return 2;
  }

  CREATE_RESPONSE(getaddrinfo);
  RESPONSE_STRING(ai->ai_canonname);
  struct addrinfo* current = ai;
  while (current) {
    char addr_str[INET6_ADDRSTRLEN];
    if (ai->ai_family == AF_INET6) {
      struct sockaddr_in6* in6 = (struct sockaddr_in6*)current->ai_addr;
      inet_ntop(
          ai->ai_family, &in6->sin6_addr.s6_addr, addr_str, sizeof(addr_str));
    } else if (ai->ai_family == AF_INET) {
      struct sockaddr_in* in = (struct sockaddr_in*)current->ai_addr;
      inet_ntop(ai->ai_family, &in->sin_addr, addr_str, sizeof(addr_str));
    }

    RESPONSE_STRING(addr_str);
    RESPONSE_STRING(ai->ai_family == AF_INET ? "AF_INET" : "AF_INET6");

    current = current->ai_next;
  }

  freeaddrinfo(ai);
  return 0;
}
Пример #10
0
int HandleSuperNET(struct PP_Var params,struct PP_Var *output,const char **out_error)
{
    char *SuperNET_JSON(char *);
    char *retstr;
    //PostMessage("inside handle SuperNET\n");
    CHECK_PARAM_COUNT(SuperNET, 1);
    PARAM_STRING(0,jsonstr);
    retstr = SuperNET_JSON(jsonstr);
    CREATE_RESPONSE(SuperNET);
    //RESPONSE_INT(0);
    RESPONSE_STRING(retstr);
    return 0;
}
Пример #11
0
static int tty_setWinPos_24(struct pvm_object me, struct data_area_4_thread *tc )
{
    DEBUG_INFO;
    struct data_area_4_tty      *da = pvm_data_area( me, tty );

    int n_param = POP_ISTACK;
    CHECK_PARAM_COUNT(n_param, 2);

    int y = POP_INT();
    int x = POP_INT();

    w_move( &(da->w), x, y );

    SYSCALL_RETURN_NOTHING;
}
Пример #12
0
/**
 * Handle a call to getcwd() made by JavaScript.
 *
 * getcwd expects 0 parameters.
 * on success, getcwd returns a result in |output|:
 *   0: "getcwd"
 *   1: the current working directory
 * on failure, getcwd returns an error string in |out_error|.
 */
int HandleGetcwd(struct PP_Var params,
                 struct PP_Var* output,
                 const char** out_error) {
  CHECK_PARAM_COUNT(getcwd, 0);

  char cwd[PATH_MAX];
  char* result = getcwd(cwd, PATH_MAX);
  if (result == NULL) {
    *out_error = PrintfToNewString("getcwd returned error: %d", errno);
    return 1;
  }

  CREATE_RESPONSE(getcwd);
  RESPONSE_STRING(cwd);
  return 0;
}
Пример #13
0
int HandleJS(struct PP_Var params, struct PP_Var* output, const char** out_error) {
  PostMessage("JS?"); 
  CHECK_PARAM_COUNT(js, 2);
  PARAM_STRING(0, jsonstr);
  PARAM_STRING(1, ptr);

  int64_t nptr = strtoll(ptr, NULL, 10);

  char * addr = (char *)nptr;

  strcpy(addr, jsonstr);

  CREATE_RESPONSE(js);
  RESPONSE_STRING(ptr);
  return 0;
}
Пример #14
0
/**
 * Handle a call to close() made by JavaScript.
 *
 * close expects 1 parameters:
 *   0: The socket file descriptor to close.
 * on success, close returns a result in |output|:
 *   0: "close"
 *   1: The socket file descriptor closed.
 * on failure, close returns an error string in |out_error|.
 */
int HandleClose(struct PP_Var params,
                struct PP_Var* output,
                const char** out_error) {
  CHECK_PARAM_COUNT(close, 1);
  PARAM_INT(0, sock);

  int result = close(sock);
  if (result != 0) {
    *out_error = PrintfToNewString("close returned error: %d", errno);
    return 1;
  }

  CREATE_RESPONSE(close);
  RESPONSE_INT(sock);
  return 0;
}
Пример #15
0
/**
 * Handle a call to chdir() made by JavaScript.
 *
 * chdir expects 1 parameter:
 *   0: The name of the directory
 * on success, chdir returns a result in |output|:
 *   0: "chdir"
 *   1: the name of the directory
 * on failure, chdir returns an error string in |out_error|.
 */
int HandleChdir(struct PP_Var params,
                struct PP_Var* output,
                const char** out_error) {
  CHECK_PARAM_COUNT(chdir, 1);
  PARAM_STRING(0, dirname);

  int result = chdir(dirname);

  if (result != 0) {
    *out_error = PrintfToNewString("chdir returned error: %d", errno);
    return 1;
  }

  CREATE_RESPONSE(chdir);
  RESPONSE_STRING(dirname);
  return 0;
}
Пример #16
0
/**
 * Handle a call to send() made by JavaScript.
 *
 * send expects 2 parameters:
 *   0: The socket file descriptor to send using.
 *   1: The NULL terminated string to send.
 * on success, send returns a result in |output|:
 *   0: "send"
 *   1: The number of bytes sent.
 * on failure, send returns an error string in |out_error|.
 */
int HandleSend(struct PP_Var params,
               struct PP_Var* output,
               const char** out_error) {
  CHECK_PARAM_COUNT(send, 2);
  PARAM_INT(0, sock);
  PARAM_STRING(1, buffer);

  int result = (int32_t)send(sock, buffer, strlen(buffer), 0);
  if (result <= 0) {
    *out_error = PrintfToNewString("send failed: %s", strerror(errno));
    return 1;
  }

  CREATE_RESPONSE(send);
  RESPONSE_INT(result);
  return 0;
}
Пример #17
0
static int gotoxy_19(struct pvm_object me , struct data_area_4_thread *tc )
{
    struct data_area_4_tty      *da = pvm_data_area( me, tty );

    DEBUG_INFO;
    int n_param = POP_ISTACK;

    CHECK_PARAM_COUNT(n_param, 2);

    int goy = POP_INT();
    int gox = POP_INT();

    da->x = da->font_width * gox;
    da->y = da->font_height * goy;

    SYSCALL_RETURN_NOTHING;
}
Пример #18
0
/**
 * Handle a call to fclose() made by JavaScript.
 *
 * fclose expects 1 parameter:
 *   0: The index of the file (which is mapped to a FILE*)
 * on success, fclose returns a result in |output|:
 *   0: "fclose"
 *   1: the file index
 * on failure, fclose returns an error string in |out_error|.
 */
int HandleFclose(struct PP_Var params,
                 struct PP_Var* output,
                 const char** out_error) {
  CHECK_PARAM_COUNT(fclose, 1);
  PARAM_FILE(0, file);

  int result = fclose(file);
  if (result) {
    *out_error = PrintfToNewString("fclose returned error %d", result);
    return 1;
  }

  RemoveFileFromMap(file_index);

  CREATE_RESPONSE(fclose);
  RESPONSE_INT(file_index);
  return 0;
}
Пример #19
0
/**
 * Handle a call to fwrite() made by JavaScript.
 *
 * fwrite expects 2 parameters:
 *   0: The index of the file (which is mapped to a FILE*)
 *   1: A string to write to the file
 * on success, fwrite returns a result in |output|:
 *   0: "fwrite"
 *   1: the file index
 *   2: the number of bytes written
 * on failure, fwrite returns an error string in |out_error|.
 */
int HandleFwrite(struct PP_Var params,
                 struct PP_Var* output,
                 const char** out_error) {
  CHECK_PARAM_COUNT(fwrite, 2);
  PARAM_FILE(0, file);
  PARAM_STRING(1, data);

  size_t bytes_written = fwrite(data, 1, data_len, file);
  if (ferror(file)) {
    *out_error = PrintfToNewString(
        "Wrote %" PRIuS " bytes, but ferror() returns true", bytes_written);
    return 1;
  }

  CREATE_RESPONSE(fwrite);
  RESPONSE_INT(file_index);
  RESPONSE_INT((int32_t)bytes_written);
  return 0;
}
Пример #20
0
static int setcolor_21(struct pvm_object me , struct data_area_4_thread *tc )
{
    (void) me;
    //struct data_area_4_tty      *da = pvm_data_area( me, tty );

    DEBUG_INFO;
    int n_param = POP_ISTACK;

    CHECK_PARAM_COUNT(n_param, 1);

    int color = POP_INT();
    (void) color;
    //int attr = (short)color;

    // TODO colors from attrs
    //printf("setcolor  font %d,%d\n", da->font_width, da->font_height );

    SYSCALL_RETURN_NOTHING;
}
Пример #21
0
/**
 * Handle a call to stat() made by JavaScript.
 *
 * stat expects 1 parameter:
 *   0: The name of the file
 * on success, stat returns a result in |output|:
 *   0: "stat"
 *   1: the file name
 *   2: the size of the file
 * on failure, stat returns an error string in |out_error|.
 */
int HandleStat(struct PP_Var params,
               struct PP_Var* output,
               const char** out_error) {
  CHECK_PARAM_COUNT(stat, 1);
  PARAM_STRING(0, filename);

  struct stat buf;
  memset(&buf, 0, sizeof(buf));
  int result = stat(filename, &buf);

  if (result == -1) {
    *out_error = PrintfToNewString("stat returned error %d", errno);
    return 1;
  }

  CREATE_RESPONSE(stat);
  RESPONSE_STRING(filename);
  RESPONSE_INT((int32_t)buf.st_size);
  return 0;
}
Пример #22
0
/**
 * Handle a call to readdir() made by JavaScript.
 *
 * readdir expects 1 parameter:
 *   0: The index of the directory (which is mapped to a DIR*)
 * on success, opendir returns a result in |output|:
 *   0: "readdir"
 *   1: the inode number of the entry
 *   2: the name of the entry
 * if there are no more entries, |output| contains:
 *   0: "readdir"
 * on failure, readdir returns an error string in |out_error|.
 */
int HandleReaddir(struct PP_Var params,
                  struct PP_Var* output,
                  const char** out_error) {
#if defined(WIN32)
  *out_error = PrintfToNewString("Win32 does not support readdir");
  return 1;
#else
  CHECK_PARAM_COUNT(readdir, 1);
  PARAM_DIR(0, dir);

  struct dirent* entry = readdir(dir);

  CREATE_RESPONSE(readdir);
  RESPONSE_INT(dir_index);
  if (entry != NULL) {
    RESPONSE_INT((int32_t)entry->d_ino);
    RESPONSE_STRING(entry->d_name);
  }
  return 0;
#endif
}
Пример #23
0
static int debug_18(struct pvm_object me , struct data_area_4_thread *tc )
{
    (void) me;
    DEBUG_INFO;

    //struct data_area_4_tty      *da = pvm_data_area( me, tty );


    int n_param = POP_ISTACK;
    CHECK_PARAM_COUNT(n_param, 1);

    struct pvm_object o = POP_ARG;

    //pvm_object_print( o );
    printf("\n\nobj dump: ");
    dumpo((addr_t)(o.data));
    printf("\n\n");

    SYS_FREE_O(o);

    SYSCALL_RETURN_NOTHING;
}
Пример #24
0
/**
 * Handle a call to closedir() made by JavaScript.
 *
 * closedir expects 1 parameter:
 *   0: The index of the directory (which is mapped to a DIR*)
 * on success, closedir returns a result in |output|:
 *   0: "closedir"
 *   1: the name of the directory
 * on failure, closedir returns an error string in |out_error|.
 */
int HandleClosedir(struct PP_Var params,
                   struct PP_Var* output,
                   const char** out_error) {
#if defined(WIN32)
  *out_error = PrintfToNewString("Win32 does not support closedir");
  return 1;
#else
  CHECK_PARAM_COUNT(closedir, 1);
  PARAM_DIR(0, dir);

  int result = closedir(dir);
  if (result) {
    *out_error = PrintfToNewString("closedir returned error %d", result);
    return 1;
  }

  RemoveDirFromMap(dir_index);

  CREATE_RESPONSE(closedir);
  RESPONSE_INT(dir_index);
  return 0;
#endif
}
Пример #25
0
static int putws_17(struct pvm_object me , struct data_area_4_thread *tc )
{
    DEBUG_INFO;

    struct data_area_4_tty      *da = pvm_data_area( me, tty );

    //printf("putws font %d,%d\n", da->font_width, da->font_height );


    int n_param = POP_ISTACK;
    CHECK_PARAM_COUNT(n_param, 1);

    struct pvm_object _text = POP_ARG;
    ASSERT_STRING(_text);

    int len = pvm_get_str_len( _text );
    const char * data = (const char *)pvm_get_str_data(_text);

    char buf[BS+2];

    if( len > BS ) len = BS;
    strncpy( buf, data, len );
    //buf[len] = '\n';
    buf[len] = 0;

    SYS_FREE_O(_text);

    //printf("tty print: '%s' at %d,%d\n", buf, da->x, da->y );

    struct rgba_t fg = da->fg;
    struct rgba_t bg = da->bg;

    w_font_tty_string( &(da->w), tty_font, buf, fg, bg, &(da->x), &(da->y) );
    drv_video_window_update( &(da->w) );

    SYSCALL_RETURN_NOTHING;
}
Пример #26
0
/**
 * Handle a call to connect() made by JavaScript.
 *
 * connect expects 2 parameters:
 *   0: The hostname to connect to.
 *   1: The port number to connect to.
 * on success, connect returns a result in |output|:
 *   0: "connect"
 *   1: The socket file descriptor.
 * on failure, connect returns an error string in |out_error|.
 */
int HandleConnect(struct PP_Var params,
                  struct PP_Var* output,
                  const char** out_error) {
  CHECK_PARAM_COUNT(connect, 2);
  PARAM_STRING(0, hostname);
  PARAM_INT(1, port);

  // Lookup host
  struct hostent* hostent = gethostbyname(hostname);
  if (hostent == NULL) {
    *out_error = PrintfToNewString("gethostbyname() returned error: %d", errno);
    return 1;
  }

  struct sockaddr_in addr;
  socklen_t addrlen = sizeof(addr);
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  memcpy(&addr.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length);

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    *out_error = PrintfToNewString("socket() failed: %s", strerror(errno));
    return 1;
  }

  int result = connect(sock, (struct sockaddr*)&addr, addrlen);
  if (result != 0) {
    *out_error = PrintfToNewString("connect() failed: %s", strerror(errno));
    close(sock);
    return 1;
  }

  CREATE_RESPONSE(connect);
  RESPONSE_INT(sock);
  return 0;
}
Пример #27
0
/**
 * Handle a call to fread() made by JavaScript.
 *
 * fread expects 2 parameters:
 *   0: The index of the file (which is mapped to a FILE*)
 *   1: The number of bytes to read from the file.
 * on success, fread returns a result in |output|:
 *   0: "fread"
 *   1: the file index
 *   2: the data read from the file
 * on failure, fread returns an error string in |out_error|.
 */
int HandleFread(struct PP_Var params,
                struct PP_Var* output,
                const char** out_error) {
  CHECK_PARAM_COUNT(fread, 2);
  PARAM_FILE(0, file);
  PARAM_INT(1, data_len);

  char* buffer = (char*)malloc(data_len + 1);
  size_t bytes_read = fread(buffer, 1, data_len, file);
  buffer[bytes_read] = 0;

  if (ferror(file)) {
    *out_error = PrintfToNewString(
        "Read %" PRIuS " bytes, but ferror() returns true", bytes_read);
    free(buffer);
    return 1;
  }

  CREATE_RESPONSE(fread);
  RESPONSE_INT(file_index);
  RESPONSE_STRING(buffer);
  free(buffer);
  return 0;
}