text: /*
   * << Haru Free PDF Library >> -- hpdf_streams.c
   *
   * URL: http://libharu.org
   *
   * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
   * Copyright (c) 2007-2008 Antony Dovgal <tony@daylessday.org>
   *
   * Permission to use, copy, modify, distribute and sell this software
   * and its documentation for any purpose is hereby granted without fee,
   * provided that the above copyright notice appear in all copies and
   * that both that copyright notice and this permission notice appear
   * in supporting documentation.
   * It is provided "as is" without express or implied warranty.
   *
   */
  
  #include <errno.h>
  
  // DQ (9/16/2009): When zlib.h is not installed we notice that "hpdf_conf.h" must preceed references to HPDF_NOZLIB.
  // This fixes a where on the NMI x86_ubuntu_5.10 platform, zlib is not installed.
  #include "hpdf_conf.h"
  
  // DQ (9/27/2009): This is the file that has the setting to disable the use of zlib (HPDF_NOZLIB)
  #include "hpdf_config.h"
  
  // DQ (9/28/2009): The inclusion of "hpdf_config.h" still is not turning ZLIB off,
  // so try this more drastic action to turn it off (this is a problem for UBUNTU systems).
  #ifndef HPDF_NOZLIB
  #define HPDF_NOZLIB 1
  #endif
  
  #ifndef HPDF_NOZLIB
  #include <zlib.h>
  #include <zconf.h>
  #endif /* HPDF_NOZLIB */
  
  // DQ (9/16/2009): Moved this to above reference to HPDF_NOZLIB.
  // #include "hpdf_conf.h"
  #include "hpdf_consts.h"
  #include "hpdf_utils.h"
  #include "hpdf_streams.h"
  
  HPDF_STATUS
  HPDF_MemStream_WriteFunc  (HPDF_Stream      stream,
                             const HPDF_BYTE  *ptr,
                             HPDF_UINT        siz);
  
  
  HPDF_STATUS
  HPDF_MemStream_SeekFunc  (HPDF_Stream      stream,
                            HPDF_INT         pos,
                            HPDF_WhenceMode  mode);
  
  
  HPDF_STATUS
  HPDF_MemStream_ReadFunc  (HPDF_Stream  stream,
                            HPDF_BYTE    *buf,
                            HPDF_UINT    *size);
  
  
  HPDF_INT32
  HPDF_MemStream_TellFunc  (HPDF_Stream  stream);
  
  
  HPDF_UINT32
  HPDF_MemStream_SizeFunc  (HPDF_Stream  stream);
  
  
  void
  HPDF_MemStream_FreeFunc  (HPDF_Stream  stream);
  
  HPDF_STATUS
  HPDF_MemStream_InWrite  (HPDF_Stream      stream,
                           const HPDF_BYTE  **ptr,
                           HPDF_UINT        *count);
  
  HPDF_STATUS
  HPDF_Stream_WriteToStreamWithDeflate  (HPDF_Stream  src,
                                         HPDF_Stream  dst,
                                         HPDF_Encrypt  e);
  
  
  HPDF_STATUS
  HPDF_FileReader_ReadFunc  (HPDF_Stream  stream,
                            HPDF_BYTE    *ptr,
                            HPDF_UINT    *siz);
  
  
  HPDF_STATUS
  HPDF_FileReader_SeekFunc  (HPDF_Stream      stream,
                             HPDF_INT         pos,
                             HPDF_WhenceMode  mode);
  
  
  HPDF_INT32
  HPDF_FileStream_TellFunc  (HPDF_Stream  stream);
  
  
  HPDF_UINT32
  HPDF_FileStream_SizeFunc  (HPDF_Stream  stream);
  
  
  HPDF_STATUS
  HPDF_FileWriter_WriteFunc  (HPDF_Stream      stream,
                              const HPDF_BYTE  *ptr,
                              HPDF_UINT        siz);
  
  void
  HPDF_FileStream_FreeFunc  (HPDF_Stream  stream);
  
  
  
  /*
   *  HPDF_Stream_Read
   *
   *  stream : Pointer to a HPDF_Stream object.
   *  ptr : Pointer to a buffer to copy read data.
   *  size : Pointer to a variable which indecates buffer size.
   *
   *  HPDF_Stream_read returns HPDF_OK when success. On failer, it returns
   *  error-code returned by reading function of this stream.
   *
   */
  
  HPDF_STATUS
  HPDF_Stream_Read  (HPDF_Stream  stream,
                     HPDF_BYTE    *ptr,
                     HPDF_UINT    *size)
  {
      if (!(stream->read_fn))
          return HPDF_SetError (stream->error, HPDF_INVALID_OPERATION, 0);
  
      /*
      if (HPDF_Error_GetCode(stream->error) != HPDF_NOERROR)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
      */
  
      return stream->read_fn(stream, ptr, size);
  }
  
  
  /*
   *  HPDF_Stream_ReadLn
   *
   *  stream : Pointer to a HPDF_Stream object.
   *  s : Pointer to a buffer to copy read data.
   *  size : buffer-size of s.
   *
   *  Read from stream until the buffer is exhausted or line-feed charactor is
   *  read.
   *
   */
  HPDF_STATUS
  HPDF_Stream_ReadLn  (HPDF_Stream  stream,
                       char    *s,
                       HPDF_UINT    *size)
  {
      char buf[HPDF_STREAM_BUF_SIZ];
      HPDF_UINT r_size = *size;
      HPDF_UINT read_size = HPDF_STREAM_BUF_SIZ;
  
      HPDF_PTRACE((" HPDF_Stream_ReadLn\n"));
  
      if (!stream || !s || *size == 0)
          return HPDF_SetError (stream->error, HPDF_INVALID_PARAMETER, 0);
  
      if (!(stream->seek_fn) || !(stream->read_fn))
          return HPDF_SetError (stream->error, HPDF_INVALID_OPERATION, 0);
  
      if (r_size < HPDF_STREAM_BUF_SIZ)
          read_size = r_size;
  
      *size = 0;
  
      while (r_size > 1) {
          char *pbuf = buf;
          HPDF_STATUS ret = HPDF_Stream_Read (stream, (HPDF_BYTE *)buf, &read_size);
  
          if (ret != HPDF_OK && read_size == 0)
              return ret;
  
          r_size -= read_size;
  
          while (read_size > 0) {
              if (*pbuf == 0x0A || *pbuf == 0x0D) {
                  *s = 0;
                  read_size--;
  
                  /* handling CR-LF marker */
                  if (*pbuf == 0x0D || read_size > 1) {
                      pbuf++;
  
                      if (*pbuf == 0x0A)
                          read_size--;
                  }
  
                  if (read_size > 0)
                      return HPDF_Stream_Seek (stream, 0 - read_size,
                                  HPDF_SEEK_CUR);
                  else
                      return HPDF_OK;
              }
  
              *s++ = *pbuf++;
              read_size--;
              (*size)++;
          }
  
          if (r_size < HPDF_STREAM_BUF_SIZ)
              read_size = r_size;
          else
              read_size = HPDF_STREAM_BUF_SIZ;
  
          if (ret == HPDF_STREAM_EOF)
              return HPDF_STREAM_EOF;
      }
  
      *s = 0;
  
      return HPDF_STREAM_READLN_CONTINUE;
  }
  
  
  /*
   * HPDF_Stream_Write
   *
   *  stream : Pointer to a HPDF_Stream object.
   *  ptr : Pointer to a buffer to write.
   *  siz : The size of buffer to write.
   *
   *  HPDF_Stream_Write returns HPDF_OK when success. On failer, it returns
   *  error-code returned by writing function of this stream.
   *
   */
  HPDF_STATUS
  HPDF_Stream_Write  (HPDF_Stream      stream,
                      const HPDF_BYTE  *ptr,
                      HPDF_UINT        size)
  {
      HPDF_STATUS ret;
  
      HPDF_PTRACE((" HPDF_Stream_Write\n"));
  
      if (!(stream->write_fn))
          return HPDF_SetError(stream->error, HPDF_INVALID_OPERATION, 0);
  
      /*
      if (HPDF_Error_GetCode(stream->error) != HPDF_NOERROR)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
      */
  
      ret = stream->write_fn(stream, ptr, size);
  
      if (ret != HPDF_OK)
          return ret;
  
      stream->size += size;
  
      return HPDF_OK;
  }
  
  
  HPDF_STATUS
  HPDF_Stream_WriteChar  (HPDF_Stream  stream,
                          char    value)
  {
      return HPDF_Stream_Write(stream, (HPDF_BYTE *)&value, sizeof(char));
  }
  
  
  HPDF_STATUS
  HPDF_Stream_WriteStr  (HPDF_Stream      stream,
                         const char  *value)
  {
      HPDF_UINT len = HPDF_StrLen(value, -1);
  
      return HPDF_Stream_Write(stream, (HPDF_BYTE *)value, len);
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteUChar  (HPDF_Stream  stream,
                           HPDF_BYTE    value)
  {
      return HPDF_Stream_Write(stream, &value, sizeof(HPDF_BYTE));
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteInt  (HPDF_Stream  stream,
                         HPDF_INT     value)
  {
      char buf[HPDF_INT_LEN + 1];
  
      char* p = HPDF_IToA(buf, value, buf + HPDF_INT_LEN);
  
      return HPDF_Stream_Write(stream, (HPDF_BYTE *)buf, (HPDF_UINT)(p - buf));
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteUInt  (HPDF_Stream  stream,
                          HPDF_UINT    value)
  {
      return HPDF_Stream_WriteInt(stream, (HPDF_INT)value);
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteReal  (HPDF_Stream  stream,
                          HPDF_REAL    value)
  {
      char buf[HPDF_REAL_LEN + 1];
  
      char* p = HPDF_FToA(buf, value, buf + HPDF_REAL_LEN);
  
      return HPDF_Stream_Write(stream, (HPDF_BYTE *)buf, (HPDF_UINT)(p - buf));
  }
  
  void
  HPDF_Stream_Free  (HPDF_Stream  stream)
  {
      if (!stream)
          return;
  
      if (stream->free_fn)
          stream->free_fn(stream);
  
      stream->sig_bytes = 0;
  
      HPDF_FreeMem(stream->mmgr, stream);
  }
  
  HPDF_STATUS
  HPDF_Stream_Seek  (HPDF_Stream      stream,
                     HPDF_INT         pos,
                     HPDF_WhenceMode  mode)
  {
      HPDF_PTRACE((" HPDF_Stream_Seek\n"));
  
      if (!(stream->seek_fn))
          return HPDF_SetError (stream->error, HPDF_INVALID_OPERATION, 0);
  
      if (HPDF_Error_GetCode(stream->error) != 0)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
  
      return stream->seek_fn(stream, pos, mode);
  }
  
  
  HPDF_INT32
  HPDF_Stream_Tell  (HPDF_Stream  stream)
  {
      HPDF_PTRACE((" HPDF_Stream_Tell\n"));
  
      if (!(stream->tell_fn))
          return HPDF_SetError (stream->error, HPDF_INVALID_OPERATION, 0);
  
      if (HPDF_Error_GetCode(stream->error) != 0)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
  
      return stream->tell_fn(stream);
  }
  
  
  HPDF_UINT32
  HPDF_Stream_Size  (HPDF_Stream  stream)
  {
      HPDF_PTRACE((" HPDF_Stream_Tell\n"));
  
      if (stream->write_fn)
          return stream->size;
  
      if (!(stream->size_fn)) {
          HPDF_SetError (stream->error, HPDF_INVALID_OPERATION, 0);
          return 0;
      }
  
      if (HPDF_Error_GetCode(stream->error) != 0)
          return 0;
  
      return stream->size_fn(stream);
  }
  
  
  HPDF_STATUS
  HPDF_Stream_WriteEscapeName  (HPDF_Stream      stream,
                                const char  *value)
  {
      char tmp_char[HPDF_LIMIT_MAX_NAME_LEN * 3 + 2];
      HPDF_UINT len;
      HPDF_INT i;
      const HPDF_BYTE* pos1;
      char* pos2;
  
      HPDF_PTRACE((" HPDF_Stream_WriteEscapeName\n"));
  
      len = HPDF_StrLen (value, HPDF_LIMIT_MAX_NAME_LEN);
      pos1 = (HPDF_BYTE*)value;
      pos2 = tmp_char;
  
      *pos2++ = '/';
      for (i = 0; i < (HPDF_INT32)len; i++) {
          HPDF_BYTE c = *pos1++;
          if (HPDF_NEEDS_ESCAPE(c)) {
              *pos2++ = '#';
              *pos2 = (char)(c >> 4);
              if (*pos2 <= 9)
                  *pos2 += 0x30;
              else
                  *pos2 += 0x41 - 10;
              pos2++;
  
              *pos2 = (char)(c & 0x0f);
              if (*pos2 <= 9)
                  *pos2 += 0x30;
              else
                  *pos2 += 0x41 - 10;
              pos2++;
          } else
              *pos2++ = c;
      }
      *pos2 = 0;
  
      return HPDF_Stream_Write (stream, (HPDF_BYTE *)tmp_char, HPDF_StrLen(tmp_char, -1));
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteEscapeText2  (HPDF_Stream    stream,
                                 const char    *text,
                                 HPDF_UINT      len)
  {
      char buf[HPDF_TEXT_DEFAULT_LEN];
      HPDF_UINT idx = 0;
      HPDF_INT i;
      const char* p = text;
      HPDF_STATUS ret;
  
      HPDF_PTRACE((" HPDF_Stream_WriteEscapeText2\n"));
  
      if (!len)
          return HPDF_OK;
  
      buf[idx++] = '(';
  
      for (i = 0; i < len; i++) {
          HPDF_BYTE c = (HPDF_BYTE)*p++;
          if (HPDF_NEEDS_ESCAPE(c)) {
              buf[idx++] = '\\';
  
              buf[idx] = c >> 6;
              buf[idx] += 0x30;
              idx++;
              buf[idx] = (c & 0x38) >> 3;
              buf[idx] += 0x30;
              idx++;
              buf[idx] = (c & 0x07);
              buf[idx] += 0x30;
              idx++;
          }
          else
              buf[idx++] = c;
  
          if (idx > HPDF_TEXT_DEFAULT_LEN - 4) {
              ret = HPDF_Stream_Write (stream, (HPDF_BYTE *)buf, idx);
              if (ret != HPDF_OK)
                  return ret;
              idx = 0;
          }
      }
      buf[idx++] = ')';
  
      ret = HPDF_Stream_Write (stream, (HPDF_BYTE *)buf, idx);
  
      return ret;
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteEscapeText  (HPDF_Stream    stream,
                                const char    *text)
  {
      HPDF_UINT len;
  
      HPDF_PTRACE((" HPDF_Stream_WriteEscapeText\n"));
  
      len = (text == NULL) ? 0 : HPDF_StrLen (text, HPDF_LIMIT_MAX_STRING_LEN);
  
      return HPDF_Stream_WriteEscapeText2(stream, text, len);
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteBinary  (HPDF_Stream      stream,
                            const HPDF_BYTE  *data,
                            HPDF_UINT        len,
                            HPDF_Encrypt     e)
  {
      char buf[HPDF_TEXT_DEFAULT_LEN];
      HPDF_BYTE ebuf[HPDF_TEXT_DEFAULT_LEN];
      HPDF_BYTE *pbuf = NULL;
      HPDF_BOOL flg = HPDF_FALSE;
      HPDF_UINT idx = 0;
      HPDF_UINT i;
      const HPDF_BYTE* p;
      HPDF_STATUS ret = HPDF_OK;
  
      HPDF_PTRACE((" HPDF_Stream_WriteBinary\n"));
  
      if (e) {
          if (len <= HPDF_TEXT_DEFAULT_LEN)
              pbuf = ebuf;
          else {
              pbuf = (HPDF_BYTE *)HPDF_GetMem (stream->mmgr, len);
              flg = HPDF_TRUE;
          }
  
          HPDF_Encrypt_CryptBuf (e, data, pbuf, len);
          p = pbuf;
      } else {
          p = data;
      }
  
      for (i = 0; i < len; i++, p++) {
          char c = *p >> 4;
  
          if (c <= 9)
              c += 0x30;
          else
              c += 0x41 - 10;
          buf[idx++] = c;
  
          c = *p & 0x0f;
          if (c <= 9)
              c += 0x30;
          else
              c += 0x41 - 10;
          buf[idx++] = c;
  
          if (idx > HPDF_TEXT_DEFAULT_LEN - 2) {
              ret = HPDF_Stream_Write (stream, (HPDF_BYTE *)buf, idx);
              if (ret != HPDF_OK) {
                  if (flg)
                      HPDF_FreeMem (stream->mmgr, pbuf);
                  return ret;
              }
              idx = 0;
          }
      }
  
      if (idx > 0) {
          ret = HPDF_Stream_Write (stream, (HPDF_BYTE *)buf, idx);
      }
  
      if (flg)
          HPDF_FreeMem (stream->mmgr, pbuf);
  
      return ret;
  }
  
  
  HPDF_STATUS
  HPDF_Stream_WriteToStreamWithDeflate  (HPDF_Stream  src,
                                         HPDF_Stream  dst,
                                         HPDF_Encrypt  e)
  {
  #ifndef HPDF_NOZLIB
  
  #define DEFLATE_BUF_SIZ  ((HPDF_INT)(HPDF_STREAM_BUF_SIZ * 1.1) + 13)
  
      HPDF_STATUS ret;
      HPDF_BOOL flg;
  
      z_stream strm;
      Bytef inbuf[HPDF_STREAM_BUF_SIZ];
      Bytef otbuf[DEFLATE_BUF_SIZ];
      HPDF_BYTE ebuf[DEFLATE_BUF_SIZ];
  
      HPDF_PTRACE((" HPDF_Stream_WriteToStreamWithDeflate\n"));
  
      /* JJW added for ROSE: the code fails on an empty input stream if this
       * block is not added */
      if (HPDF_Stream_Size (src) == 0)
          return HPDF_OK;
  
      /* initialize input stream */
      ret = HPDF_Stream_Seek (src, 0, HPDF_SEEK_SET);
      if (ret != HPDF_OK)
          return ret;
  
      /* initialize decompression stream. */
      HPDF_MemSet(&strm, 0x00, sizeof(z_stream));
      strm.next_out = otbuf;
      strm.avail_out = DEFLATE_BUF_SIZ;
  
      ret = deflateInit_(&strm, Z_DEFAULT_COMPRESSION, ZLIB_VERSION,
              sizeof(z_stream));
      if (ret != Z_OK)
          return HPDF_SetError (src->error, HPDF_ZLIB_ERROR, ret);
  
      strm.next_in = inbuf;
      strm.avail_in = 0;
  
      flg = HPDF_FALSE;
      for (;;) {
          HPDF_UINT size = HPDF_STREAM_BUF_SIZ;
  
          ret = HPDF_Stream_Read (src, inbuf, &size);
  
          strm.next_in = inbuf;
          strm.avail_in = size;
  
          if (ret != HPDF_OK) {
              if (ret == HPDF_STREAM_EOF) {
                  flg = HPDF_TRUE;
                  if (size == 0)
                      break;
              } else {
                  deflateEnd(&strm);
                  return ret;
              }
          }
  
          while (strm.avail_in > 0) {
              ret = deflate(&strm, Z_NO_FLUSH);
              if (ret != Z_OK && ret != Z_STREAM_END) {
                  deflateEnd(&strm);
                  return HPDF_SetError (src->error, HPDF_ZLIB_ERROR, ret);
              }
  
              if (strm.avail_out == 0) {
                  if (e) {
                      HPDF_Encrypt_CryptBuf (e, otbuf, ebuf, DEFLATE_BUF_SIZ);
                      ret = HPDF_Stream_Write(dst, ebuf, DEFLATE_BUF_SIZ);
                  } else
                      ret = HPDF_Stream_Write (dst, otbuf, DEFLATE_BUF_SIZ);
  
                  if (ret != HPDF_OK) {
                      deflateEnd(&strm);
                      return HPDF_SetError (src->error, HPDF_ZLIB_ERROR, ret);
                  }
  
                  strm.next_out = otbuf;
                  strm.avail_out = DEFLATE_BUF_SIZ;
              }
          }
  
          if (flg)
              break;
      }
  
      flg = HPDF_FALSE;
      for (;;) {
          ret = deflate(&strm, Z_FINISH);
          if (ret != Z_OK && ret != Z_STREAM_END) {
              deflateEnd(&strm);
              return HPDF_SetError (src->error, HPDF_ZLIB_ERROR, ret);
          }
  
          if (ret == Z_STREAM_END)
              flg = HPDF_TRUE;
  
          if (strm.avail_out < DEFLATE_BUF_SIZ) {
              HPDF_UINT osize = DEFLATE_BUF_SIZ - strm.avail_out;
              if (e) {
                  HPDF_Encrypt_CryptBuf (e, otbuf, ebuf, osize);
                  ret = HPDF_Stream_Write(dst, ebuf, osize);
              } else
                  ret = HPDF_Stream_Write (dst, otbuf, osize);
  
              if (ret != HPDF_OK) {
                  deflateEnd(&strm);
                  return HPDF_SetError (src->error, HPDF_ZLIB_ERROR, ret);
              }
  
              strm.next_out = otbuf;
              strm.avail_out = DEFLATE_BUF_SIZ;
          }
  
          if (flg)
              break;
      }
  
      deflateEnd(&strm);
      return HPDF_OK;
  #else /* HPDF_NOZLIB */
      return HPDF_UNSUPPORTED_FUNC;
  #endif /* HPDF_NOZLIB */
  }
  
  HPDF_STATUS
  HPDF_Stream_WriteToStream  (HPDF_Stream  src,
                              HPDF_Stream  dst,
                              HPDF_UINT    filter,
                              HPDF_Encrypt  e)
  {
      HPDF_STATUS ret;
      HPDF_BYTE buf[HPDF_STREAM_BUF_SIZ];
      HPDF_BYTE ebuf[HPDF_STREAM_BUF_SIZ];
      HPDF_BOOL flg;
  
      HPDF_PTRACE((" HPDF_Stream_WriteToStream\n"));
  
      if (!dst || !(dst->write_fn)) {
          HPDF_SetError (src->error, HPDF_INVALID_OBJECT, 0);
          return HPDF_INVALID_OBJECT;
      }
  
      if (HPDF_Error_GetCode (src->error) != HPDF_NOERROR ||
              HPDF_Error_GetCode (dst->error) != HPDF_NOERROR)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
  
  #ifndef HPDF_NOZLIB
      if (filter & HPDF_STREAM_FILTER_FLATE_DECODE)
          return HPDF_Stream_WriteToStreamWithDeflate (src, dst, e);
  #endif /* HPDF_NOZLIB */
  
      /* initialize input stream */
      if (HPDF_Stream_Size (src) == 0)
          return HPDF_OK;
  
      ret = HPDF_Stream_Seek (src, 0, HPDF_SEEK_SET);
      if (ret != HPDF_OK)
          return ret;
  
      flg = HPDF_FALSE;
      for (;;) {
          HPDF_UINT size = HPDF_STREAM_BUF_SIZ;
  
          ret = HPDF_Stream_Read (src, buf, &size);
  
          if (ret != HPDF_OK) {
              if (ret == HPDF_STREAM_EOF) {
                  flg = HPDF_TRUE;
                  if (size == 0)
                      break;
              } else {
                  return ret;
              }
          }
  
          if (e) {
              HPDF_Encrypt_CryptBuf (e, buf, ebuf, size);
              ret = HPDF_Stream_Write(dst, ebuf, size);
          } else {
              ret = HPDF_Stream_Write(dst, buf, size);
          }
  
          if (ret != HPDF_OK)
              return ret;
  
          if (flg)
              break;
      }
  
      return HPDF_OK;
  }
  
  HPDF_Stream
  HPDF_FileReader_New  (HPDF_MMgr   mmgr,
                        const char  *fname)
  {
      HPDF_Stream stream;
      HPDF_FILEP fp = HPDF_FOPEN (fname, "rb");
  
      HPDF_PTRACE((" HPDF_FileReader_New\n"));
  
      if (!fp) {
          HPDF_SetError (mmgr->error, HPDF_FILE_OPEN_ERROR, errno);
          return NULL;
      }
  
      stream = (HPDF_Stream)HPDF_GetMem(mmgr, sizeof(HPDF_Stream_Rec));
  
      if (stream) {
          HPDF_MemSet(stream, 0, sizeof(HPDF_Stream_Rec));
          stream->sig_bytes = HPDF_STREAM_SIG_BYTES;
          stream->type = HPDF_STREAM_FILE;
          stream->error = mmgr->error;
          stream->mmgr = mmgr;
          stream->read_fn = HPDF_FileReader_ReadFunc;
          stream->seek_fn = HPDF_FileReader_SeekFunc;
          stream->tell_fn = HPDF_FileStream_TellFunc;
          stream->size_fn = HPDF_FileStream_SizeFunc;
          stream->free_fn = HPDF_FileStream_FreeFunc;
          stream->attr = fp;
      }
  
      return stream;
  }
  
  /*
   *  HPDF_FileReader_ReadFunc
   *
   *  Reading data function for HPDF_FileReader.
   *
   */
  
  HPDF_STATUS
  HPDF_FileReader_ReadFunc  (HPDF_Stream  stream,
                            HPDF_BYTE    *ptr,
                            HPDF_UINT    *siz)
  {
      HPDF_FILEP fp = (HPDF_FILEP)stream->attr;
      HPDF_UINT rsiz;
  
      HPDF_PTRACE((" HPDF_FileReader_ReadFunc\n"));
  
      HPDF_MemSet(ptr, 0, *siz);
      rsiz = HPDF_FREAD(ptr, 1, *siz, fp);
  
      if (rsiz != *siz) {
          if (HPDF_FEOF(fp)) {
  
              *siz = rsiz;
  
              return HPDF_STREAM_EOF;
          }
  
          return HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR, HPDF_FERROR(fp));
      }
  
      return HPDF_OK;
  }
  
  /*
   *  HPDF_FileReader_SeekFunc
   *
   *  Seeking data function for HPDF_FileReader.
   *
   *  stream : Pointer to a HPDF_Stream object.
   *  pos : New position of stream object.
   *  HPDF_whence_mode : Seeking mode describing below.
   *                     HPDF_SEEK_SET : Absolute file position
   *                     HPDF_SEEK_CUR : Relative to the current file position
   *                     HPDF_SEEK_END : Relative to the current end of file.
   *
   *  HPDF_FileReader_seek_fn returns HPDF_OK when successful. On failer
   *  the result is HPDF_FILE_IO_ERROR and HPDF_Error_GetCode2() returns the
   *  error which returned by file seeking function of platform.
   *
   */
  
  HPDF_STATUS
  HPDF_FileReader_SeekFunc  (HPDF_Stream     stream,
                             HPDF_INT         pos,
                             HPDF_WhenceMode  mode)
  {
      HPDF_FILEP fp = (HPDF_FILEP)stream->attr;
      HPDF_INT whence;
  
      HPDF_PTRACE((" HPDF_FileReader_SeekFunc\n"));
  
      switch (mode) {
          case HPDF_SEEK_CUR:
              whence = SEEK_CUR;
              break;
          case HPDF_SEEK_END:
              whence = SEEK_END;
              break;
          default:
              whence = SEEK_SET;
      }
  
      if (HPDF_FSEEK (fp, pos, whence) != 0) {
          return HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR, HPDF_FERROR(fp));
      }
  
      return HPDF_OK;
  }
  
  
  HPDF_INT32
  HPDF_FileStream_TellFunc  (HPDF_Stream   stream)
  {
      HPDF_INT32 ret;
      HPDF_FILEP fp = (HPDF_FILEP)stream->attr;
  
      HPDF_PTRACE((" HPDF_FileReader_TellFunc\n"));
  
      if ((ret = HPDF_FTELL (fp)) < 0) {
          return HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR,
                  HPDF_FERROR(fp));
      }
  
      return ret;
  }
  
  
  HPDF_UINT32
  HPDF_FileStream_SizeFunc  (HPDF_Stream   stream)
  {
      HPDF_INT size;
      HPDF_INT ptr;
      HPDF_FILEP fp = (HPDF_FILEP)stream->attr;
  
      HPDF_PTRACE((" HPDF_FileReader_SizeFunc\n"));
  
      /* save current file-pointer */
      if ((ptr = HPDF_FTELL (fp)) < 0) {
          HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR,
                  HPDF_FERROR(fp));
          return 0;
      }
  
      /* move file-pointer to the end of the file */
      if (HPDF_FSEEK (fp, 0, SEEK_END) < 0) {
          HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR,
                  HPDF_FERROR(fp));
          return 0;
      }
  
      /* get the pointer of the end of the file */
      if ((size = HPDF_FTELL (fp)) < 0) {
          HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR,
                  HPDF_FERROR(fp));
          return 0;
      }
  
      /* restore current file-pointer */
      if (HPDF_FSEEK (fp, ptr, SEEK_SET) < 0) {
          HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR,
                  HPDF_FERROR(fp));
          return 0;
      }
  
      return (HPDF_UINT32)size;
  }
  
  
  HPDF_Stream
  HPDF_FileWriter_New  (HPDF_MMgr        mmgr,
                        const char  *fname)
  {
      HPDF_Stream stream;
      HPDF_FILEP fp = HPDF_FOPEN (fname, "wb");
  
      HPDF_PTRACE((" HPDF_FileWriter_New\n"));
  
      if (!fp) {
          HPDF_SetError (mmgr->error, HPDF_FILE_OPEN_ERROR, errno);
          return NULL;
      }
  
      stream = (HPDF_Stream)HPDF_GetMem (mmgr, sizeof(HPDF_Stream_Rec));
  
      if (stream) {
          HPDF_MemSet (stream, 0, sizeof(HPDF_Stream_Rec));
          stream->sig_bytes = HPDF_STREAM_SIG_BYTES;
          stream->error = mmgr->error;
          stream->mmgr = mmgr;
          stream->write_fn = HPDF_FileWriter_WriteFunc;
          stream->free_fn = HPDF_FileStream_FreeFunc;
          stream->tell_fn = HPDF_FileStream_TellFunc;
          stream->attr = fp;
          stream->type = HPDF_STREAM_FILE;
      }
  
      return stream;
  }
  
  HPDF_STATUS
  HPDF_FileWriter_WriteFunc  (HPDF_Stream      stream,
                              const HPDF_BYTE  *ptr,
                              HPDF_UINT        siz)
  {
      HPDF_FILEP fp;
      HPDF_UINT ret;
  
      HPDF_PTRACE((" HPDF_FileWriter_WriteFunc\n"));
  
      fp = (HPDF_FILEP)stream->attr;
      ret = HPDF_FWRITE (ptr, 1, siz, fp);
  
      if (ret != siz) {
          return HPDF_SetError (stream->error, HPDF_FILE_IO_ERROR, HPDF_FERROR(fp));
      }
  
      return HPDF_OK;
  }
  
  
  void
  HPDF_FileStream_FreeFunc  (HPDF_Stream  stream)
  {
      HPDF_FILEP fp;
  
      HPDF_PTRACE((" HPDF_FileStream_FreeFunc\n"));
  
      fp = (HPDF_FILEP)stream->attr;
  
      if (fp)
          HPDF_FCLOSE(fp);
  
      stream->attr = NULL;
  }
  
  HPDF_STATUS
  HPDF_MemStream_InWrite  (HPDF_Stream      stream,
                           const HPDF_BYTE  **ptr,
                           HPDF_UINT        *count)
  {
      HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)stream->attr;
      HPDF_UINT rsize = attr->buf_siz - attr->w_pos;
  
      HPDF_PTRACE((" HPDF_MemStream_InWrite\n"));
  
      if (*count <= 0)
          return HPDF_OK;
  
      if (rsize >= *count) {
          HPDF_MemCpy (attr->w_ptr, *ptr, *count);
          attr->w_ptr += *count;
          attr->w_pos += *count;
          *count = 0;
      } else {
          if (rsize > 0) {
              HPDF_MemCpy (attr->w_ptr, *ptr, rsize);
              *ptr += rsize;
              *count -= rsize;
          }
          attr->w_ptr = (HPDF_BYTE*)HPDF_GetMem (stream->mmgr, attr->buf_siz);
  
          if (attr->w_ptr == NULL)
             return HPDF_Error_GetCode (stream->error);
  
          if (HPDF_List_Add (attr->buf, attr->w_ptr) != HPDF_OK) {
              HPDF_FreeMem (stream->mmgr, attr->w_ptr);
              attr->w_ptr = NULL;
  
              return HPDF_Error_GetCode (stream->error);
          }
          attr->w_pos = 0;
      }
      return HPDF_OK;
  }
  
  
  HPDF_STATUS
  HPDF_MemStream_WriteFunc  (HPDF_Stream      stream,
                             const HPDF_BYTE  *ptr,
                             HPDF_UINT        siz)
  {
      HPDF_UINT wsiz = siz;
  
      HPDF_PTRACE((" HPDF_MemStream_WriteFunc\n"));
  
      if (HPDF_Error_GetCode (stream->error) != 0)
          return HPDF_THIS_FUNC_WAS_SKIPPED;
  
      while (wsiz > 0) {
          HPDF_STATUS ret = HPDF_MemStream_InWrite (stream, &ptr, &wsiz);
          if (ret != HPDF_OK)
              return ret;
      }
  
      return HPDF_OK;
  }
  
  
  HPDF_INT32
  HPDF_MemStream_TellFunc  (HPDF_Stream  stream)
  {
      HPDF_INT32 ret;
      HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)stream->attr;
  
      HPDF_PTRACE((" HPDF_MemStream_TellFunc\n"));
  
      ret = attr->r_ptr_idx * attr->buf_siz;
      ret += attr->r_pos;
  
      return ret;
  }
  
  
  HPDF_UINT32
  HPDF_MemStream_SizeFunc  (HPDF_Stream  stream)
  {
      HPDF_PTRACE((" HPDF_MemStream_SizeFunc\n"));
  
      return stream->size;
  }
  
  HPDF_STATUS
  HPDF_MemStream_SeekFunc  (HPDF_Stream      stream,
                            HPDF_INT         pos,
                            HPDF_WhenceMode  mode)
  {
      HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)stream->attr;
  
      HPDF_PTRACE((" HPDF_MemStream_SeekFunc\n"));
  
      if (mode == HPDF_SEEK_CUR) {
          pos += (attr->r_ptr_idx * attr->buf_siz);
          pos += attr->r_pos;
      } else if (mode == HPDF_SEEK_END)
          pos = stream->size - pos;
  
      if (pos > stream->size || stream->size == 0)
          return HPDF_SetError (stream->error, HPDF_STREAM_EOF, 0);
  
      attr->r_ptr_idx = pos / attr->buf_siz;
      attr->r_pos = pos % attr->buf_siz;
      attr->r_ptr = (HPDF_BYTE*)HPDF_List_ItemAt (attr->buf, attr->r_ptr_idx);
      if (attr->r_ptr == NULL) {
          HPDF_SetError (stream->error, HPDF_INVALID_OBJECT, 0);
          return HPDF_INVALID_OBJECT;
      } else
          attr->r_ptr += attr->r_pos;
  
      return HPDF_OK;
  }
  
  
  HPDF_BYTE*
  HPDF_MemStream_GetBufPtr  (HPDF_Stream  stream,
                             HPDF_UINT    index,
                             HPDF_UINT    *length)
  {
      HPDF_BYTE *ret;
      HPDF_MemStreamAttr attr;
  
      HPDF_PTRACE((" HPDF_MemStream_GetBufPtr\n"));
  
      if (stream->type != HPDF_STREAM_MEMORY) {
          HPDF_SetError (stream->error, HPDF_INVALID_OBJECT, 0);
          return NULL;
      }
  
      attr = (HPDF_MemStreamAttr)stream->attr;
  
      ret = (HPDF_BYTE *)HPDF_List_ItemAt (attr->buf, index);
      if (ret == NULL) {
          HPDF_SetError (stream->error, HPDF_INVALID_PARAMETER, 0);
          *length = 0;
          return NULL;
      }
  
      *length = (attr->buf->count - 1 == index) ? attr->w_pos : attr->buf_siz;
      return ret;
  }
  
  
  void
  HPDF_MemStream_FreeData  (HPDF_Stream  stream)
  {
      HPDF_MemStreamAttr attr;
      HPDF_UINT i;
  
      HPDF_PTRACE((" HPDF_MemStream_FreeData\n"));
  
      if (!stream || stream->type != HPDF_STREAM_MEMORY)
          return;
  
      attr = (HPDF_MemStreamAttr)stream->attr;
  
      for (i = 0; i < attr->buf->count; i++)
          HPDF_FreeMem (stream->mmgr, HPDF_List_ItemAt (attr->buf, i));
  
      HPDF_List_Clear(attr->buf);
  
      stream->size = 0;
      attr->w_pos = attr->buf_siz;
      attr->w_ptr = NULL;
      attr->r_ptr_idx = 0;
      attr->r_pos = 0;
  }
  
  void
  HPDF_MemStream_FreeFunc  (HPDF_Stream  stream)
  {
      HPDF_MemStreamAttr attr;
  
      HPDF_PTRACE((" HPDF_MemStream_FreeFunc\n"));
  
      attr = (HPDF_MemStreamAttr)stream->attr;
      HPDF_MemStream_FreeData (stream);
      HPDF_List_Free (attr->buf);
      HPDF_FreeMem (stream->mmgr, attr);
      stream->attr = NULL;
  }
  
  HPDF_Stream
  HPDF_MemStream_New  (HPDF_MMgr  mmgr,
                       HPDF_UINT  buf_siz)
  {
      HPDF_Stream stream;
  
      HPDF_PTRACE((" HPDF_MemStream_New\n"));
  
      // Create new HPDF_Stream object.
      stream = (HPDF_Stream)HPDF_GetMem (mmgr, sizeof(HPDF_Stream_Rec));
  
      if (stream) {
          // Create attribute struct.
          HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)HPDF_GetMem (mmgr,
                  sizeof(HPDF_MemStreamAttr_Rec));
  
          if (!attr) {
              HPDF_FreeMem (mmgr, stream);
              return NULL;
          }
  
          HPDF_MemSet (stream, 0, sizeof(HPDF_Stream_Rec));
          HPDF_MemSet (attr, 0, sizeof(HPDF_MemStreamAttr_Rec));
  
          attr->buf = HPDF_List_New (mmgr, HPDF_DEF_ITEMS_PER_BLOCK);
          if (!attr->buf) {
              HPDF_FreeMem (mmgr, stream);
              HPDF_FreeMem (mmgr, attr);
              return NULL;
          }
  
          stream->sig_bytes = HPDF_STREAM_SIG_BYTES;
          stream->type = HPDF_STREAM_MEMORY;
          stream->error = mmgr->error;
          stream->mmgr = mmgr;
          stream->attr = attr;
          attr->buf_siz = (buf_siz > 0) ? buf_siz : HPDF_STREAM_BUF_SIZ;
          attr->w_pos = attr->buf_siz;
  
          stream->write_fn = HPDF_MemStream_WriteFunc;
          stream->read_fn = HPDF_MemStream_ReadFunc;
          stream->seek_fn = HPDF_MemStream_SeekFunc;
          stream->tell_fn = HPDF_MemStream_TellFunc;
          stream->size_fn = HPDF_MemStream_SizeFunc;
          stream->free_fn = HPDF_MemStream_FreeFunc;
      }
  
      return stream;
  }
  
  HPDF_UINT
  HPDF_MemStream_GetBufSize  (HPDF_Stream  stream)
  {
      HPDF_MemStreamAttr attr;
  
      HPDF_PTRACE((" HPDF_MemStream_GetBufSize\n"));
  
      if (!stream || stream->type != HPDF_STREAM_MEMORY)
          return 0;
  
      attr = (HPDF_MemStreamAttr)stream->attr;
      return attr->buf_siz;
  }
  
  HPDF_UINT
  HPDF_MemStream_GetBufCount  (HPDF_Stream  stream)
  {
      HPDF_MemStreamAttr attr;
  
      HPDF_PTRACE((" HPDF_MemStream_GetBufCount\n"));
  
      if (!stream || stream->type != HPDF_STREAM_MEMORY)
          return 0;
  
      attr = (HPDF_MemStreamAttr)stream->attr;
      return attr->buf->count;
  }
  
  HPDF_STATUS
  HPDF_MemStream_ReadFunc  (HPDF_Stream  stream,
                            HPDF_BYTE    *buf,
                            HPDF_UINT    *size)
  {
      HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)stream->attr;
      HPDF_UINT buf_size;
      HPDF_UINT rlen = *size;
  
      HPDF_PTRACE((" HPDF_MemStream_ReadFunc\n"));
  
      *size = 0;
  
      while (rlen > 0) {
          HPDF_UINT tmp_len;
  
          if (attr->buf->count == 0)
              return HPDF_STREAM_EOF;
  
          if (attr->buf->count - 1 > attr->r_ptr_idx)
              tmp_len = attr->buf_siz - attr->r_pos;
          else if (attr->buf->count - 1 == attr->r_ptr_idx)
              tmp_len = attr->w_pos - attr->r_pos;
          else
              return HPDF_STREAM_EOF;
  
          if (!attr->r_ptr)
              attr->r_ptr = (HPDF_BYTE*)HPDF_List_ItemAt (attr->buf,
                              attr->r_ptr_idx);
  
          if (tmp_len >= rlen) {
              HPDF_MemCpy (buf, attr->r_ptr, rlen);
              attr->r_pos += rlen;
              *size += rlen;
              attr->r_ptr += rlen;
              return HPDF_OK;
          } else {
              buf = HPDF_MemCpy (buf, attr->r_ptr, tmp_len);
              rlen -= tmp_len;
              *size += tmp_len;
  
              if (attr->r_ptr_idx == attr->buf->count - 1) {
                  attr->r_ptr += tmp_len;
                  attr->r_pos += tmp_len;
                  return HPDF_STREAM_EOF;
              }
  
              attr->r_ptr_idx++;
              attr->r_pos = 0;
              attr->r_ptr = HPDF_MemStream_GetBufPtr (stream, attr->r_ptr_idx,
                      &buf_size);
          }
      }
  
      return HPDF_OK;
  }
  
  
  HPDF_STATUS
  HPDF_MemStream_Rewrite  (HPDF_Stream  stream,
                           HPDF_BYTE    *buf,
                           HPDF_UINT    size)
  {
      HPDF_MemStreamAttr attr = (HPDF_MemStreamAttr)stream->attr;
      HPDF_UINT buf_size;
      HPDF_UINT rlen = size;
  
      HPDF_PTRACE((" HPDF_MemStream_Rewrite\n"));
  
      while (rlen > 0) {
          HPDF_UINT tmp_len;
  
          if (attr->buf->count <= attr->r_ptr_idx) {
              HPDF_STATUS ret = HPDF_MemStream_WriteFunc (stream, buf, rlen);
              attr->r_ptr_idx = attr->buf->count;
              attr->r_pos = attr->w_pos;
              attr->r_ptr = attr->w_ptr;
              return ret;
          } else if (attr->buf->count == attr->r_ptr_idx)
              tmp_len = attr->w_pos - attr->r_pos;
          else
              tmp_len = attr->buf_siz - attr->r_pos;
  
          if (tmp_len >= rlen) {
              HPDF_MemCpy(attr->r_ptr, buf, rlen);
              attr->r_pos += rlen;
              attr->r_ptr += rlen;
              return HPDF_OK;
          } else {
              HPDF_MemCpy(attr->r_ptr, buf, tmp_len);
              buf += tmp_len;
              rlen -= tmp_len;
              attr->r_ptr_idx++;
  
              if (attr->buf->count > attr->r_ptr_idx) {
                  attr->r_pos = 0;
                  attr->r_ptr = HPDF_MemStream_GetBufPtr (stream, attr->r_ptr_idx,
                          &buf_size);
              }
          }
      }
      return HPDF_OK;
  }
  
  /*
   *  HPDF_CallbackReader_new
   *
   *  Constractor for HPDF_CallbackReader.
   *
   *  mmgr : Pointer to a HPDF_MMgr object.
   *  read_fn : Pointer to a user function for reading data.
   *  seek_fn : Pointer to a user function for seeking data.
   *  data : Pointer to a data which defined by user.
   *
   *  return: If success, It returns pointer to new HPDF_Stream object,
   *          otherwise, it returns NULL.
   *
   */
  
  
  HPDF_Stream
  HPDF_CallbackReader_New  (HPDF_MMgr              mmgr,
                            HPDF_Stream_Read_Func  read_fn,
                            HPDF_Stream_Seek_Func  seek_fn,
                            HPDF_Stream_Tell_Func  tell_fn,
                            HPDF_Stream_Size_Func  size_fn,
                            void*                  data)
  {
      HPDF_Stream stream;
  
      HPDF_PTRACE((" HPDF_CallbackReader_New\n"));
  
      stream = (HPDF_Stream)HPDF_GetMem (mmgr, sizeof(HPDF_Stream_Rec));
  
      if (stream) {
          HPDF_MemSet (stream, 0, sizeof(HPDF_Stream_Rec));
          stream->sig_bytes = HPDF_STREAM_SIG_BYTES;
          stream->error = mmgr->error;
          stream->mmgr = mmgr;
          stream->read_fn = read_fn;
          stream->seek_fn = seek_fn;
          stream->tell_fn = tell_fn;
          stream->size_fn = size_fn;
          stream->attr = data;
          stream->type = HPDF_STREAM_CALLBACK;
      }
  
      return stream;
  }
  
  /*
   *  HPDF_CallbackWriter_new
   *
   *  Constractor for HPDF_CallbackWriter.
   *
   *  mmgr : Pointer to a HPDF_MMgr object.
   *  read_fn : Pointer to a user function for writing data.
   *  data : Pointer to a data which defined by user.
   *
   *  return: If success, It returns pointer to new HPDF_Stream object,
   *          otherwise, it returns NULL.
   *
   */
  
  
  HPDF_Stream
  HPDF_CallbackWriter_New (HPDF_MMgr               mmgr,
                           HPDF_Stream_Write_Func  write_fn,
                           void*                   data)
  {
      HPDF_Stream stream;
  
      HPDF_PTRACE((" HPDF_CallbackWriter_New\n"));
  
      stream = (HPDF_Stream)HPDF_GetMem (mmgr, sizeof(HPDF_Stream_Rec));
  
      if (stream) {
          HPDF_MemSet (stream, 0, sizeof(HPDF_Stream_Rec));
          stream->sig_bytes = HPDF_STREAM_SIG_BYTES;
          stream->error = mmgr->error;
          stream->mmgr = mmgr;
          stream->write_fn = write_fn;
          stream->attr = data;
          stream->type = HPDF_STREAM_CALLBACK;
      }
  
      return stream;
  }
  
  
  
  HPDF_STATUS
  HPDF_Stream_Validate  (HPDF_Stream  stream)
  {
      if (!stream || stream->sig_bytes != HPDF_STREAM_SIG_BYTES)
          return HPDF_FALSE;
      else
          return HPDF_TRUE;
  }
  
  