/**
   * Parses given sequence of bytes and constructs a message object from it.
   *
   * @param mesBytes the byte array that should be parsed
   * @param startIdx an index of <code>mesBytes</code> array to start the parsing at
   * @param mes an object to write a result to, should already be created
   * @return updated index of <code>mesBytes</code> array
   * @throws DomainProtocolException if some error has occurred
   */
  public static int parseMessage(byte[] mesBytes, int startIdx, Message mesObj)
      throws DomainProtocolException {
    int idx = startIdx;
    int tmp, tmp2;
    int qdCnt;
    int anCnt;
    int nsCnt;
    int arCnt;

    if (mesObj == null) {
      // jndi.58=The value of parameter mesObj is null
      throw new DomainProtocolException(Messages.getString("jndi.58")); // $NON-NLS-1$
    }
    // header section
    // ID
    mesObj.setId(ProviderMgr.parse16Int(mesBytes, idx));
    idx += 2;
    // QR & opCode & AA & TC & RD & RA & Z & rCode
    tmp = ProviderMgr.parse16Int(mesBytes, idx);
    idx += 2;
    // QR
    mesObj.setQR(ProviderMgr.checkBit(tmp, ProviderConstants.QR_MASK));
    // OPCODE
    tmp2 = (tmp & ProviderConstants.OPCODE_MASK) >> ProviderConstants.OPCODE_SHIFT;
    mesObj.setOpCode(tmp2);
    // AA
    mesObj.setAA(ProviderMgr.checkBit(tmp, ProviderConstants.AA_MASK));
    // TC
    mesObj.setTc(ProviderMgr.checkBit(tmp, ProviderConstants.TC_MASK));
    // RD
    mesObj.setRD(ProviderMgr.checkBit(tmp, ProviderConstants.RD_MASK));
    // RA
    mesObj.setRA(ProviderMgr.checkBit(tmp, ProviderConstants.RA_MASK));
    // RCODE
    tmp2 = (tmp & ProviderConstants.RCODE_MASK) >> ProviderConstants.RCODE_SHIFT;
    mesObj.setRCode(tmp2);
    // QDCOUNT
    qdCnt = ProviderMgr.parse16Int(mesBytes, idx);
    mesObj.setQDCount(qdCnt);
    idx += 2;
    // ANCOUNT
    anCnt = ProviderMgr.parse16Int(mesBytes, idx);
    mesObj.setANCount(anCnt);
    idx += 2;
    // NSCOUNT
    nsCnt = ProviderMgr.parse16Int(mesBytes, idx);
    mesObj.setNSCount(nsCnt);
    idx += 2;
    // ARCOUNT
    arCnt = ProviderMgr.parse16Int(mesBytes, idx);
    mesObj.setARCount(arCnt);
    idx += 2;
    // question section
    for (int i = 0; i < qdCnt; i++) {
      QuestionRecord qr = new QuestionRecord();
      idx = QuestionRecord.parseRecord(mesBytes, idx, qr);
      mesObj.addQuestionRecord(qr);
    }
    // answer section
    for (int i = 0; i < anCnt; i++) {
      ResourceRecord rr = new ResourceRecord();
      idx = ResourceRecord.parseRecord(mesBytes, idx, rr);
      mesObj.addAnswerRR(rr);
    }
    // authority section
    for (int i = 0; i < nsCnt; i++) {
      ResourceRecord rr = new ResourceRecord();
      idx = ResourceRecord.parseRecord(mesBytes, idx, rr);
      mesObj.addAuthorityRR(rr);
    }
    // additional section
    for (int i = 0; i < arCnt; i++) {
      ResourceRecord rr = new ResourceRecord();
      idx = ResourceRecord.parseRecord(mesBytes, idx, rr);
      mesObj.addAdditionalRR(rr);
    }
    return idx;
  }
  /**
   * Generates sequence of bytes that represents the message.
   *
   * @param buffer the buffer to write bytes into
   * @param startIdx the index of <code>buffer</code> to start writing at
   * @return updated index of the <code>buffer</code>
   * @throws DomainProtocolException if something went wrong
   */
  public int writeBytes(byte[] buffer, int startIdx) throws DomainProtocolException {
    int idx = startIdx;
    int tmp = 0;

    // basic check
    if (buffer == null) {
      // jndi.32=buffer is null
      throw new DomainProtocolException(Messages.getString("jndi.32")); // $NON-NLS-1$
    }
    // ID
    idx = ProviderMgr.write16Int(id, buffer, idx);
    // QR
    tmp = ProviderMgr.setBit(tmp, ProviderConstants.QR_MASK, qr);
    // OPCODE
    tmp &= ~ProviderConstants.OPCODE_MASK;
    tmp |= (opCode & 0xf) << ProviderConstants.OPCODE_SHIFT;
    // AA
    tmp = ProviderMgr.setBit(tmp, ProviderConstants.AA_MASK, aa);
    // TC
    tmp = ProviderMgr.setBit(tmp, ProviderConstants.TC_MASK, tc);
    // RD
    tmp = ProviderMgr.setBit(tmp, ProviderConstants.RD_MASK, rd);
    // RA
    tmp = ProviderMgr.setBit(tmp, ProviderConstants.RA_MASK, ra);
    // Z, drop all those bits
    tmp &= ~ProviderConstants.Z_MASK;
    // RCODE
    tmp &= ~ProviderConstants.RCODE_MASK;
    tmp |= (rCode & 0xf) << ProviderConstants.RCODE_SHIFT;
    // write to buffer
    idx = ProviderMgr.write16Int(tmp, buffer, idx);
    // QDCOUNT
    idx = ProviderMgr.write16Int(qdCount, buffer, idx);
    // ANCOUNT
    idx = ProviderMgr.write16Int(anCount, buffer, idx);
    // NSCOUNT
    idx = ProviderMgr.write16Int(nsCount, buffer, idx);
    // ARCOUNT
    idx = ProviderMgr.write16Int(arCount, buffer, idx);
    // question section
    for (int i = 0; i < questionRecords.size(); i++) {
      QuestionRecord qr = questionRecords.elementAt(i);

      idx = qr.writeBytes(buffer, idx);
    }
    // answer section
    for (int i = 0; i < answerRRs.size(); i++) {
      ResourceRecord rr = answerRRs.elementAt(i);

      idx = rr.writeBytes(buffer, idx);
    }
    // authority section
    for (int i = 0; i < authorityRRs.size(); i++) {
      ResourceRecord rr = answerRRs.elementAt(i);

      idx = rr.writeBytes(buffer, idx);
    }
    // additional section
    for (int i = 0; i < additionalRRs.size(); i++) {
      ResourceRecord rr = answerRRs.elementAt(i);

      idx = rr.writeBytes(buffer, idx);
    }
    return idx;
  }