content: package com.genersoft.iot.vmp.gb28181.bean;
  
  import gov.nist.core.Host;
  import gov.nist.core.HostNameParser;
  import gov.nist.javax.sip.SIPConstants;
  import gov.nist.javax.sip.address.AddressImpl;
  import gov.nist.javax.sip.address.GenericURI;
  import gov.nist.javax.sip.address.SipUri;
  import gov.nist.javax.sip.address.TelephoneNumber;
  import gov.nist.javax.sip.header.*;
  import gov.nist.javax.sip.message.SIPMessage;
  import gov.nist.javax.sip.message.SIPRequest;
  import gov.nist.javax.sip.message.SIPResponse;
  import gov.nist.javax.sip.parser.*;
  import lombok.extern.slf4j.Slf4j;
  
  import java.io.UnsupportedEncodingException;
  import java.text.ParseException;
  
  @Slf4j
  public class GBStringMsgParser implements MessageParser {
  
      protected static boolean computeContentLengthFromMessage = false;
  
      /**
       * @since v0.9
       */
      public GBStringMsgParser() {
          super();
      }
  
      /**
       * Parse a buffer containing a single SIP Message where the body is an array
       * of un-interpreted bytes. This is intended for parsing the message from a
       * memory buffer when the buffer. Incorporates a bug fix for a bug that was
       * noted by Will Sullin of Callcast
       *
       * @param msgBuffer
       *            a byte buffer containing the messages to be parsed. This can
       *            consist of multiple SIP Messages concatenated together.
       * @return a SIPMessage[] structure (request or response) containing the
       *         parsed SIP message.
       * @exception ParseException
       *                is thrown when an illegal message has been encountered
       *                (and the rest of the buffer is discarded).
       * @see ParseExceptionListener
       */
      public SIPMessage parseSIPMessage(byte[] msgBuffer, boolean readBody, boolean strict, ParseExceptionListener parseExceptionListener) throws ParseException {
          if (msgBuffer == null || msgBuffer.length == 0)
              return null;
  
          int i = 0;
  
          // Squeeze out any leading control character.
          try {
              while (msgBuffer[i] < 0x20)
                  i++;
          }
          catch (ArrayIndexOutOfBoundsException e) {
              // Array contains only control char, return null.
              if (log.isDebugEnabled()) {
                  log.debug("handled only control char so returning null");
              }
              return null;
          }
  
          // Iterate thru the request/status line and headers.
          String currentLine = null;
          String currentHeader = null;
          boolean isFirstLine = true;
          SIPMessage message = null;
          do
          {
              int lineStart = i;
  
              // Find the length of the line.
              try {
                  while (msgBuffer[i] != '\r' && msgBuffer[i] != '\n')
                      i++;
              }
              catch (ArrayIndexOutOfBoundsException e) {
                  // End of the message.
                  break;
              }
              int lineLength = i - lineStart;
  
              // Make it a String.
              try {
                  currentLine = new String(msgBuffer, lineStart, lineLength, "UTF-8");
              } catch (UnsupportedEncodingException e) {
                  throw new ParseException("Bad message encoding!", 0);
              }
  
              currentLine = trimEndOfLine(currentLine);
  
              if (currentLine.length() == 0) {
                  // Last header line, process the previous buffered header.
                  if (currentHeader != null && message != null) {
                      processHeader(currentHeader, message, parseExceptionListener, msgBuffer);
                  }
  
              }
              else {
                  if (isFirstLine) {
                      message = processFirstLine(currentLine, parseExceptionListener, msgBuffer);
                  } else {
                      char firstChar = currentLine.charAt(0);
                      if (firstChar == '\t' || firstChar == ' ') {
                          if (currentHeader == null)
                              throw new ParseException("Bad header continuation.", 0);
  
                          // This is a continuation, append it to the previous line.
                          currentHeader += currentLine.substring(1);
                      }
                      else {
                          if (currentHeader != null && message != null) {
                              processHeader(currentHeader, message, parseExceptionListener, msgBuffer);
                          }
                          currentHeader = currentLine;
                      }
                  }
              }
  
              if (msgBuffer[i] == '\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\n')
                  i++;
  
              i++;
  
              isFirstLine = false;
          } while (currentLine.length() > 0); // End do - while
  
          if (message == null) throw new ParseException("Bad message", 0);
          message.setSize(i);
  
          // Check for content legth header
          if (readBody && message.getContentLength() != null ) {
              if ( message.getContentLength().getContentLength() != 0) {
                  int bodyLength = msgBuffer.length - i;
  
                  byte[] body = new byte[bodyLength];
                  System.arraycopy(msgBuffer, i, body, 0, bodyLength);
                  message.setMessageContent(body,!strict,computeContentLengthFromMessage,message.getContentLength().getContentLength());
              } else if (message.getCSeqHeader().getMethod().equalsIgnoreCase("MESSAGE")) {
                  int bodyLength = msgBuffer.length - i;
  
                  byte[] body = new byte[bodyLength];
                  System.arraycopy(msgBuffer, i, body, 0, bodyLength);
                  message.setMessageContent(body,!strict,computeContentLengthFromMessage,bodyLength);
              }else if (!computeContentLengthFromMessage && strict) {
                  String last4Chars = new String(msgBuffer, msgBuffer.length - 4, 4);
                  if(!"\r\n\r\n".equals(last4Chars)) {
                      throw new ParseException("Extraneous characters at the end of the message ",i);
                  }
              }
          }
  
          return message;
      }
  
      protected static String trimEndOfLine(String line) {
          if (line == null)
              return line;
  
          int i = line.length() - 1;
          while (i >= 0 && line.charAt(i) <= 0x20)
              i--;
  
          if (i == line.length() - 1)
              return line;
  
          if (i == -1)
              return "";
  
          return line.substring(0, i+1);
      }
  
      protected SIPMessage processFirstLine(String firstLine, ParseExceptionListener parseExceptionListener, byte[] msgBuffer) throws ParseException {
          SIPMessage message;
          if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) {
              message = new SIPRequest();
              try {
                  RequestLine requestLine = new RequestLineParser(firstLine + "\n")
                          .parse();
                  ((SIPRequest) message).setRequestLine(requestLine);
              } catch (ParseException ex) {
                  if (parseExceptionListener != null)
                      try {
                          parseExceptionListener.handleException(ex, message,
                                  RequestLine.class, firstLine, new String(msgBuffer, "UTF-8"));
                      } catch (UnsupportedEncodingException e) {
                          e.printStackTrace();
                      }
                  else
                      throw ex;
  
              }
          } else {
              message = new SIPResponse();
              try {
                  StatusLine sl = new StatusLineParser(firstLine + "\n").parse();
                  ((SIPResponse) message).setStatusLine(sl);
              } catch (ParseException ex) {
                  if (parseExceptionListener != null) {
                      try {
                          parseExceptionListener.handleException(ex, message,
                                  StatusLine.class, firstLine, new String(msgBuffer, "UTF-8"));
                      } catch (UnsupportedEncodingException e) {
                          e.printStackTrace();
                      }
                  } else
                      throw ex;
  
              }
          }
          return message;
      }
  
      protected void processHeader(String header, SIPMessage message, ParseExceptionListener parseExceptionListener, byte[] rawMessage) throws ParseException {
          if (header == null || header.length() == 0)
              return;
  
          HeaderParser headerParser = null;
          try {
              headerParser = ParserFactory.createParser(header + "\n");
          } catch (ParseException ex) {
              // https://java.net/jira/browse/JSIP-456
              if (parseExceptionListener != null) {
                  parseExceptionListener.handleException(ex, message, null,
                          header, null);
                  return;
              } else {
                  throw ex;
              }
          }
  
          try {
              SIPHeader sipHeader = headerParser.parse();
              message.attachHeader(sipHeader, false);
          } catch (ParseException ex) {
              if (parseExceptionListener != null) {
                  String headerName = Lexer.getHeaderName(header);
                  Class headerClass = NameMap.getClassFromName(headerName);
                  if (headerClass == null) {
                      headerClass = ExtensionHeaderImpl.class;
  
                  }
                  try {
                      parseExceptionListener.handleException(ex, message,
                              headerClass, header, new String(rawMessage, "UTF-8"));
                  } catch (UnsupportedEncodingException e) {
                      e.printStackTrace();
                  }
  
              }
          }
      }
  
      /**
       * Parse an address (nameaddr or address spec) and return and address
       * structure.
       *
       * @param address
       *            is a String containing the address to be parsed.
       * @return a parsed address structure.
       * @since v1.0
       * @exception ParseException
       *                when the address is badly formatted.
       */
      public AddressImpl parseAddress(String address) throws ParseException {
          AddressParser addressParser = new AddressParser(address);
          return addressParser.address(true);
      }
  
      /**
       * Parse a host:port and return a parsed structure.
       *
       * @param hostport
       *            is a String containing the host:port to be parsed
       * @return a parsed address structure.
       * @since v1.0
       * @exception throws
       *                a ParseException when the address is badly formatted.
       *
      public HostPort parseHostPort(String hostport) throws ParseException {
      Lexer lexer = new Lexer("charLexer", hostport);
      return new HostNameParser(lexer).hostPort();
  
      }
       */
  
      /**
       * Parse a host name and return a parsed structure.
       *
       * @param host
       *            is a String containing the host name to be parsed
       * @return a parsed address structure.
       * @since v1.0
       * @exception ParseException
       *                a ParseException when the hostname is badly formatted.
       */
      public Host parseHost(String host) throws ParseException {
          Lexer lexer = new Lexer("charLexer", host);
          return new HostNameParser(lexer).host();
  
      }
  
      /**
       * Parse a telephone number return a parsed structure.
       *
       * @param telephone_number
       *            is a String containing the telephone # to be parsed
       * @return a parsed address structure.
       * @since v1.0
       * @exception ParseException
       *                a ParseException when the address is badly formatted.
       */
      public TelephoneNumber parseTelephoneNumber(String telephone_number)
              throws ParseException {
          // Bug fix contributed by Will Scullin
          return new URLParser(telephone_number).parseTelephoneNumber(true);
  
      }
  
      /**
       * Parse a SIP url from a string and return a URI structure for it.
       *
       * @param url
       *            a String containing the URI structure to be parsed.
       * @return A parsed URI structure
       * @exception ParseException
       *                if there was an error parsing the message.
       */
  
      public SipUri parseSIPUrl(String url) throws ParseException {
          try {
              return new URLParser(url).sipURL(true);
          } catch (ClassCastException ex) {
              throw new ParseException(url + " Not a SIP URL ", 0);
          }
      }
  
      /**
       * Parse a uri from a string and return a URI structure for it.
       *
       * @param url
       *            a String containing the URI structure to be parsed.
       * @return A parsed URI structure
       * @exception ParseException
       *                if there was an error parsing the message.
       */
  
      public GenericURI parseUrl(String url) throws ParseException {
          return new URLParser(url).parse();
      }
  
      /**
       * Parse an individual SIP message header from a string.
       *
       * @param header
       *            String containing the SIP header.
       * @return a SIPHeader structure.
       * @exception ParseException
       *                if there was an error parsing the message.
       */
      public static SIPHeader parseSIPHeader(String header) throws ParseException {
          int start = 0;
          int end = header.length() - 1;
          try {
              // Squeeze out any leading control character.
              while (header.charAt(start) <= 0x20)
                  start++;
  
              // Squeeze out any trailing control character.
              while (header.charAt(end) <= 0x20)
                  end--;
          }
          catch (ArrayIndexOutOfBoundsException e) {
              // Array contains only control char.
              throw new ParseException("Empty header.", 0);
          }
  
          StringBuilder buffer = new StringBuilder(end + 1);
          int i = start;
          int lineStart = start;
          boolean endOfLine = false;
          while (i <= end) {
              char c = header.charAt(i);
              if (c == '\r' || c == '\n') {
                  if (!endOfLine) {
                      buffer.append(header.substring(lineStart, i));
                      endOfLine = true;
                  }
              }
              else {
                  if (endOfLine) {
                      endOfLine = false;
                      if (c == ' ' || c == '\t') {
                          buffer.append(' ');
                          lineStart = i + 1;
                      }
                      else {
                          lineStart = i;
                      }
                  }
              }
  
              i++;
          }
          buffer.append(header.substring(lineStart, i));
          buffer.append('\n');
  
          HeaderParser hp = ParserFactory.createParser(buffer.toString());
          if (hp == null)
              throw new ParseException("could not create parser", 0);
          return hp.parse();
      }
  
      /**
       * Parse the SIP Request Line
       *
       * @param requestLine
       *            a String containing the request line to be parsed.
       * @return a RequestLine structure that has the parsed RequestLine
       * @exception ParseException
       *                if there was an error parsing the requestLine.
       */
  
      public RequestLine parseSIPRequestLine(String requestLine)
              throws ParseException {
          requestLine += "\n";
          return new RequestLineParser(requestLine).parse();
      }
  
      /**
       * Parse the SIP Response message status line
       *
       * @param statusLine
       *            a String containing the Status line to be parsed.
       * @return StatusLine class corresponding to message
       * @exception ParseException
       *                if there was an error parsing
       * @see StatusLine
       */
  
      public StatusLine parseSIPStatusLine(String statusLine)
              throws ParseException {
          statusLine += "\n";
          return new StatusLineParser(statusLine).parse();
      }
  
      public static void setComputeContentLengthFromMessage(
              boolean computeContentLengthFromMessage) {
          GBStringMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage;
      }
  }
  