⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pchannel.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/*
 * pchannel.cxx
 *
 * Operating System utilities.
 *
 * Portable Windows Library
 *
 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * $Log: pchannel.cxx,v $
 * Revision 1.1  2006/06/29 04:18:19  joegenbaclor
 * *** empty log message ***
 *
 * Revision 1.36  2005/11/30 12:47:42  csoutheren
 * Removed tabs, reformatted some code, and changed tags for Doxygen
 *
 * Revision 1.35  2005/10/06 08:20:14  csoutheren
 * Changed WriteString to ensure it always writes all data even with partial writes
 *
 * Revision 1.34  2005/09/18 11:05:36  dominance
 * include/ptlib/channel.h, include/ptlib/pstring.h, src/ptlib/common/contain.cxx,
 * src/ptlib/common/pchannel.cxx:
 * correct the STL defined checking to use proper syntax.
 *
 * include/ptlib/object.h:
 * re-add typedef to compile on mingw
 *
 * make/ptlib-config.in:
 * import a long-standing fix from the Debian packs which allows usage of
 * ptlib-config without manually adding -lpt for each of the subsequent
 * projects
 *
 * Revision 1.33  2005/08/05 20:41:42  csoutheren
 * Added unix support for scattered read/write
 *
 * Revision 1.32  2004/07/03 03:00:46  rjongbloed
 * Fixed MSVC warning
 *
 * Revision 1.31  2004/07/03 01:48:28  rjongbloed
 * Fixed memory leak caused by buggy iostream, can't do init twice. Thanks Norbert Bartalsky
 *
 * Revision 1.30  2004/06/08 01:31:08  csoutheren
 * Make the test sense correct for the init(NULL)
 *
 * Revision 1.29  2004/06/08 01:29:00  csoutheren
 * Removed memory leak on VS.net caused by unobvious iostream allocation
 *
 * Revision 1.28  2004/04/09 06:38:11  rjongbloed
 * Fixed compatibility with STL based streams, eg as used by VC++2003
 *
 * Revision 1.27  2004/04/03 08:22:21  csoutheren
 * Remove pseudo-RTTI and replaced with real RTTI
 *
 * Revision 1.26  2004/03/22 10:15:28  rjongbloed
 * Added classes similar to PWaitAndSignal to automatically unlock a PReadWriteMutex
 *   when goes out of scope.
 *
 * Revision 1.25  2004/02/24 11:19:32  rjongbloed
 * Fixed seekpos() function on channel to read data when seeking beyond end of corrent stream.
 *
 * Revision 1.24  2003/12/19 04:31:27  csoutheren
 * Changed GetLastReadCount and GetLastWriteCount to be virtual
 *
 * Revision 1.23  2003/04/23 00:37:04  craigs
 * More casts to avoid problems on MacOSX thanks to Shawn Hsiao
 *
 * Revision 1.22  2003/03/19 00:10:24  robertj
 * Added ability to use seekoff() in a PChannel streambuf that is not a file.
 *
 * Revision 1.21  2003/02/11 07:22:43  robertj
 * Fixed strange behaviour in ReadString(P_MAX_INDEX) with DOS text files where
 *   it would get extra garbage at the end of the string, thanks Joerg Schoemer.
 *
 * Revision 1.20  2003/02/10 01:01:03  robertj
 * Fixed portability issue for lseek() calls, should just look for -1 return
 *   value to indicate error, thanks Joerg Schoemer
 *
 * Revision 1.19  2002/12/19 03:37:05  craigs
 * Simplified PChannel::WriteString
 *
 * Revision 1.18  2002/04/09 02:30:18  robertj
 * Removed GCC3 variable as __GNUC__ can be used instead, thanks jason Spence
 *
 * Revision 1.17  2002/01/26 23:57:45  craigs
 * Changed for GCC 3.0 compatibility, thanks to manty@manty.net
 *
 * Revision 1.16  2001/11/13 04:13:22  robertj
 * Added ability to adjust size of ios buffer on PChannels.
 *
 * Revision 1.15  2001/09/27 10:23:42  craigs
 * CHanged ReadString to allow read until end of input with P_MAX_INDEX arg
 *
 * Revision 1.14  2001/09/11 02:36:52  robertj
 * Fixed crash bug when ReadString() gets I/O error.
 *
 * Revision 1.13  2001/09/10 21:58:31  craigs
 * Fixed cut and paste problem that broke PIndirectChannel::Write
 *
 * Revision 1.12  2001/09/10 02:51:23  robertj
 * Major change to fix problem with error codes being corrupted in a
 *   PChannel when have simultaneous reads and writes in threads.
 *
 * Revision 1.11  2001/06/04 10:13:38  robertj
 * Added compare function to compare value of os_handle.
 * Added has function based on os_handle value.
 *
 * Revision 1.10  2001/01/02 06:07:07  robertj
 * Fixed race condition in reopening indirect channel, thanks Bertrand Croq.
 *
 * Revision 1.9  2000/11/14 08:25:58  robertj
 * Added function to propagate the error text through to indirect channel.
 *
 * Revision 1.8  2000/08/22 08:33:37  robertj
 * Removed PAssert() for write to unattached indirect channel, now sets
 *    return code so is similay to "unopened file" semantics.
 *
 * Revision 1.7  2000/06/26 11:17:20  robertj
 * Nucleus++ port (incomplete).
 *
 * Revision 1.6  1999/07/06 08:55:05  robertj
 * Fixed bug in PFile::Copy, does not write last chunk of data to new file.
 *
 * Revision 1.5  1999/06/17 14:44:42  robertj
 * Fixed incorrect comparison of open write channel
 *
 * Revision 1.4  1999/06/17 13:38:11  robertj
 * Fixed race condition on indirect channel close, mutex needed in PIndirectChannel.
 *
 * Revision 1.3  1999/02/22 10:10:12  robertj
 * Changed channel output flush to remove double Write() call.
 *
 * Revision 1.2  1999/01/31 00:57:18  robertj
 * Fixed bug when opening an already open file, should close it!
 *
 * Revision 1.1  1998/11/30 12:46:19  robertj
 * Initial revision
 *
 */

#include <ptlib.h>

#include <ctype.h>


///////////////////////////////////////////////////////////////////////////////
// PChannel

PChannelStreamBuffer::PChannelStreamBuffer(PChannel * chan)
  : channel(PAssertNULL(chan))
{
}


BOOL PChannelStreamBuffer::SetBufferSize(PINDEX newSize)
{
  return input.SetSize(newSize) && output.SetSize(newSize);
}


int PChannelStreamBuffer::overflow(int c)
{
  if (pbase() == NULL) {
    char * p = output.GetPointer(1024);
    setp(p, p+output.GetSize());
  }

  int bufSize = pptr() - pbase();
  if (bufSize > 0) {
    setp(pbase(), epptr());
    if (!channel->Write(pbase(), bufSize))
      return EOF;
  }

  if (c != EOF) {
    *pptr() = (char)c;
    pbump(1);
  }

  return 0;
}


int PChannelStreamBuffer::underflow()
{
  if (eback() == NULL) {
    char * p = input.GetPointer(1024);
    char * e = p+input.GetSize();
    setg(p, e, e);
  }

  if (gptr() != egptr())
    return (BYTE)*gptr();

  if (!channel->Read(eback(), egptr() - eback()) ||
                                  channel->GetErrorCode() != PChannel::NoError)
    return EOF;

  PINDEX count = channel->GetLastReadCount();
  char * p = egptr() - count;
  memmove(p, eback(), count);
  setg(eback(), p, egptr());
  return (BYTE)*p;
}


int PChannelStreamBuffer::sync()
{
  int inAvail = egptr() - gptr();
  if (inAvail > 0) {
    setg(eback(), egptr(), egptr());
    if (PIsDescendant(channel, PFile))
      ((PFile *)channel)->SetPosition(-inAvail, PFile::Current);
  }

  if (pptr() > pbase())
    return overflow();

  return 0;
}


#ifdef __USE_STL__
streampos PChannelStreamBuffer::seekoff(off_type off, ios_base::seekdir dir, ios_base::openmode)
#else
streampos PChannelStreamBuffer::seekoff(streamoff off, ios::seek_dir dir, int)
#endif
{
  sync();
  if (PIsDescendant(channel, PFile)) {
    PFile * file = (PFile *)channel;
    file->SetPosition(off, (PFile::FilePositionOrigin)dir);
    return file->GetPosition();
  }

  // If we have an input stream and the buffer is empty then force a read so
  // we can seek ahead.
  if (egptr() == gptr()) {
    int c = underflow();
    if (c == EOF)
      return EOF;
  }

  while (off-- > 0) {
    if (sbumpc() == EOF)
      return EOF;
  }
    
  return egptr() - gptr();
}


#ifdef __USE_STL__
streampos PChannelStreamBuffer::seekpos(pos_type pos, ios_base::openmode mode)
{
  return seekoff(pos, ios_base::beg, mode);
}
#endif


#ifdef _MSC_VER
#pragma warning(disable:4355)
#endif

PChannel::PChannel()
  : iostream(new PChannelStreamBuffer(this)),
    readTimeout(PMaxTimeInterval), writeTimeout(PMaxTimeInterval)
{
  os_handle = -1;
  memset(lastErrorCode, 0, sizeof(lastErrorCode));
  memset(lastErrorNumber, 0, sizeof(lastErrorNumber));
  lastReadCount = lastWriteCount = 0;
  Construct();
}

#ifdef _MSC_VER
#pragma warning(default:4355)
#endif


PChannel::~PChannel()
{
  flush();
  Close();
  delete (PChannelStreamBuffer *)rdbuf();
#ifndef _WIN32
  init(NULL);
#endif
}

PObject::Comparison PChannel::Compare(const PObject & obj) const
{
  PAssert(PIsDescendant(&obj, PChannel), PInvalidCast);
  int h1 = GetHandle();
  int h2 = ((const PChannel&)obj).GetHandle();
  if (h1 < h2)
    return LessThan;
  if (h1 > h2)
    return GreaterThan;
  return EqualTo;
}


PINDEX PChannel::HashFunction() const
{
  return GetHandle()%97;
}


BOOL PChannel::IsOpen() const
{
  return os_handle >= 0;
}

PINDEX PChannel::GetLastReadCount() const
{ 
  return lastReadCount; 
}

PINDEX PChannel::GetLastWriteCount() const
{ 
  return lastWriteCount; 
}

int PChannel::ReadChar()
{
  BYTE c;
  BOOL retVal = Read(&c, 1);
  return (retVal && lastReadCount == 1) ? c : -1;
}


int PChannel::ReadCharWithTimeout(PTimeInterval & timeout)
{
  SetReadTimeout(timeout);
  PTimeInterval startTick = PTimer::Tick();
  int c;
  if ((c = ReadChar()) < 0) // Timeout or aborted
    return -1;
  timeout -= PTimer::Tick() - startTick;
  return c;
}


BOOL PChannel::ReadBlock(void * buf, PINDEX len)
{
  char * ptr = (char *)buf;
  PINDEX numRead = 0;

  while (numRead < len && Read(ptr+numRead, len - numRead))
    numRead += lastReadCount;

  lastReadCount = numRead;

  return lastReadCount == len;
}


PString PChannel::ReadString(PINDEX len)
{
  PString str;

  if (len == P_MAX_INDEX) {
    PINDEX l = 0;
    for (;;) {
      char * p = l + str.GetPointer(l+1000+1);
      if (!Read(p, 1000))
        break;
      l += lastReadCount;
    }
    str.SetSize(l+1);

    /*Need to put in a null at the end to allow for MSDOS/Win32 text files
      which returns fewer bytes than actually read as it shrinks the data into
      the removed carriage returns, so it actually changes the buffer beyond
      what it indicated. */
    str[l] = '\0';
  }
  else {
    if (!ReadBlock(str.GetPointer(len+1), len))
      return PString::Empty();
  }

  return str;
}


BOOL PChannel::WriteString(const PString & str)
{
  PINDEX len = str.GetLength();
  PINDEX written = 0;
  while (written < len) {
    if (!Write((const char *)str + written, len - written)) {
      lastWriteCount += written;
      return FALSE;
    }
    written += lastWriteCount;
  }
  lastWriteCount = written;
  return TRUE;
}


BOOL PChannel::ReadAsync(void * buf, PINDEX len)
{
  BOOL retVal = Read(buf, len);
  OnReadComplete(buf, lastReadCount);
  return retVal;
}


void PChannel::OnReadComplete(void *, PINDEX)
{
}


BOOL PChannel::WriteChar(int c)
{
  PAssert(c >= 0 && c < 256, PInvalidParameter);
  char buf = (char)c;
  return Write(&buf, 1);
}


BOOL PChannel::WriteAsync(const void * buf, PINDEX len)
{
  BOOL retVal = Write(buf, len);
  OnWriteComplete(buf, lastWriteCount);
  return retVal;
}


void PChannel::OnWriteComplete(const void *, PINDEX)
{
}


BOOL PChannel::SetBufferSize(PINDEX newSize)
{
  return ((PChannelStreamBuffer *)rdbuf())->SetBufferSize(newSize);
}


enum {
  NextCharEndOfString = -1,
  NextCharDelay = -2,
  NextCharSend = -3,
  NextCharWait = -4
};


static int HexDigit(char c)
{
  if (!isxdigit(c))
    return 0;

  int hex = c - '0';
  if (hex < 10)
    return hex;

  hex -= 'A' - '9' - 1;
  if (hex < 16)
    return hex;

  return hex - ('a' - 'A');
}


static int GetNextChar(const PString & command,
                                    PINDEX & pos, PTimeInterval * time = NULL)
{
  int temp;

  if (command[pos] == '\0')
    return NextCharEndOfString;

  if (command[pos] != '\\')
    return command[pos++];

  switch (command[++pos]) {
    case '\0' :
      return NextCharEndOfString;

    case 'a' : // alert (ascii value 7)
      pos++;
      return 7;

    case 'b' : // backspace (ascii value 8)
      pos++;
      return 8;

    case 'f' : // formfeed (ascii value 12)
      pos++;
      return 12;

    case 'n' : // newline (ascii value 10)
      pos++;
      return 10;

    case 'r' : // return (ascii value 13)
      pos++;
      return 13;

    case 't' : // horizontal tab (ascii value 9)
      pos++;
      return 9;

    case 'v' : // vertical tab (ascii value 11)
      pos++;
      return 11;

    case 'x' : // followed by hh  where nn is hex number (ascii value 0xhh)
      if (isxdigit(command[++pos])) {
        temp = HexDigit(command[pos++]);
        if (isxdigit(command[pos]))
          temp += HexDigit(command[pos++]);
        return temp;
      }
      return command[pos];

    case 's' :
      pos++;
      return NextCharSend;

    case 'd' : // ns  delay for n seconds/milliseconds
    case 'w' :
      temp = command[pos] == 'd' ? NextCharDelay : NextCharWait;
      long milliseconds = 0;
      while (isdigit(command[++pos]))
        milliseconds = milliseconds*10 + command[pos] - '0';
      if (milliseconds <= 0)
        milliseconds = 1;
      if (command[pos] == 'm')
        pos++;
      else {
        milliseconds *= 1000;
        if (command[pos] == 's')
          pos++;
      }
      if (time != NULL)
        *time = milliseconds;
      return temp;
  }

  if (command[pos] < '0' || command[pos] > '7')
    return command[pos++];

  // octal number

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -