MessageRef ReadZipFile(DataIO & readFrom, bool loadData)
{
   TCHECKPOINT;

   static const int NAME_BUF_LEN = 8*1024;  // names longer than 8KB are ridiculous anyway!
   char * nameBuf = newnothrow_array(char, NAME_BUF_LEN);
   if (nameBuf)
   {
      MessageRef ret = GetMessageFromPool();
      if (ret())
      {
         zlib_filefunc_def zdefs = {
            fopen_dataio_func,
            fread_dataio_func,
            fwrite_dataio_func,
            ftell_dataio_func,
            fseek_dataio_func,
            fclose_dataio_func,
            ferror_dataio_func,
            &readFrom
         };
         zipFile zf = unzOpen2(NULL, &zdefs);
         if (zf != NULL)
         {
            if (ReadZipFileAux(zf, *ret(), nameBuf, NAME_BUF_LEN, loadData) != B_NO_ERROR) ret.Reset();
            unzClose(zf);
         }
         else ret.Reset();  // failure!
      }
      delete [] nameBuf;
      return ret;
   }
   else WARN_OUT_OF_MEMORY;

   return MessageRef();
}
int32
PlainTextMessageIOGateway ::
DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes)
{
   TCHECKPOINT;

   int32 ret = 0;
   const int tempBufSize = 2048;
   char buf[tempBufSize];

   const uint32 mtuSize = GetMaximumPacketSize();
   if (mtuSize > 0)
   {
      // Packet-IO implementation
      char * pbuf  = buf;
      int pbufSize = tempBufSize;

      ByteBufferRef bigBuf;
      if (mtuSize > tempBufSize)
      {
         // Just in case our MTU size is too big for our on-stack buffer
         bigBuf = GetByteBufferFromPool(mtuSize);
         if (bigBuf())
         {
            pbuf     = (char *) bigBuf()->GetBuffer();
            pbufSize = bigBuf()->GetNumBytes();
         }
      }

      while(true)
      {
         IPAddressAndPort sourceIAP;
         const int32 bytesRead = GetPacketDataIO()->ReadFrom(pbuf, muscleMin(maxBytes, (uint32)(pbufSize-1)), sourceIAP);
              if (bytesRead < 0) return (ret > 0) ? ret : -1;
         else if (bytesRead > 0)
         {
            uint32 filteredBytesRead = bytesRead;
            FilterInputBuffer(pbuf, filteredBytesRead, pbufSize-1);
            ret += filteredBytesRead;
            pbuf[filteredBytesRead] = '\0';

            bool prevCharWasCarriageReturn = false;  // deliberately a local var, since UDP packets should be independent of each other
            MessageRef inMsg;  // demand-allocated
            int32 beginAt = 0;
            for (uint32 i=0; i<filteredBytesRead; i++)
            {
               char nextChar = pbuf[i];
               if ((nextChar == '\r')||(nextChar == '\n'))
               {
                  pbuf[i] = '\0';  // terminate the string here
                  if ((nextChar == '\r')||(prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]);
                  beginAt = i+1;
               }
               prevCharWasCarriageReturn = (nextChar == '\r');
            }
            if (beginAt < (int32)filteredBytesRead) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]);
            if (inMsg()) 
            {
               (void) inMsg()->AddFlat(PR_NAME_PACKET_REMOTE_LOCATION, sourceIAP);
               receiver.CallMessageReceivedFromGateway(inMsg);
               inMsg.Reset();
            }
            ret += bytesRead;
         }
         else return ret;
      }
   }
   else
   {
      // Stream-IO implementation
      const int32 bytesRead = GetDataIO()()->Read(buf, muscleMin(maxBytes, (uint32)(sizeof(buf)-1)));
      if (bytesRead < 0)
      {
         FlushInput(receiver);
         return -1;
      }
      if (bytesRead > 0)
      {
         uint32 filteredBytesRead = bytesRead;
         FilterInputBuffer(buf, filteredBytesRead, sizeof(buf)-1);
         ret += filteredBytesRead;
         buf[filteredBytesRead] = '\0';

         MessageRef inMsg;  // demand-allocated
         int32 beginAt = 0;
         for (uint32 i=0; i<filteredBytesRead; i++)
         {
            char nextChar = buf[i];
            if ((nextChar == '\r')||(nextChar == '\n'))
            {
               buf[i] = '\0';  // terminate the string here
               if ((nextChar == '\r')||(_prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &buf[beginAt]);
               beginAt = i+1;
            }
            _prevCharWasCarriageReturn = (nextChar == '\r');
         }
         if (beginAt < (int32)filteredBytesRead)
         {
            if (_flushPartialIncomingLines) inMsg = AddIncomingText(inMsg, &buf[beginAt]);
                                       else _incomingText += &buf[beginAt];
         }
         if (inMsg()) receiver.CallMessageReceivedFromGateway(inMsg);
      }
   }
   return ret;
}