Package center.system.msg

Source Code of center.system.msg.SAMsg$MessageOutputStream

package center.system.msg;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import ru.vassaev.core.PrmInterface;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.io.ByteMsg;
import ru.vassaev.core.io.CloseableOutputStream;
import ru.vassaev.core.types.StringList;
import ru.vassaev.core.util.Bytes;
import ru.vassaev.core.util.Strings;

public class SAMsg extends ByteMsg {
  public static final byte SOH = 0x01;
  public static final byte STX = 0x02;
  public static final byte EOT = 0x04;
  public static final byte ENQ = 0x05;
  public static final byte ACK = 0x06;
  public static final byte CR =  0x0D;
  public static final byte NAK = 0x15;
 
  private int len = 0;
  private int lenh = 0;

  public static String charset = "ibm866";
 
  private final Map<Integer, byte[]> data = new HashMap<Integer, byte[]>();
  private final Map<Integer, byte[]> header = new HashMap<Integer, byte[]>();

  public int getType() {
    return type;
  }

  public void reset() {
    data.clear();
    header.clear();
    type = 0;
    len = 0;
    lenh = 0;
  }

  private byte type = ENQ;
  public ArrayList<byte[]> getMsg() throws SysException {
    ArrayList<byte[]> r = new ArrayList<byte[]>();
    byte[] add;
    byte[] val;
    r.add(new byte[] { type });
    if (type != STX && type != SOH)
      return r;
    byte[] la = new byte[2];
    r.add(la);
    int lhi = 0;
    if (type == SOH) {
      byte[] lh = new byte[2];
      r.add(lh);
      for (Map.Entry<Integer, byte[]> e : header.entrySet()) {
        val = e.getValue();
        add = new byte[3 + val.length];
        add[0] = e.getKey().byteValue();
        byte[] l = Bytes.intToByte16Revers(val.length);
        add[1] = l[0];
        add[2] = l[1];
        System.arraycopy(val, 0, add, 3, val.length);
        lhi += add.length;
        r.add(add);
      }
      byte[] l = Bytes.intToByte16Revers(lhi);
      lh[0] = l[0];
      lh[1] = l[1];
      lhi += 2;
    }
    for (Map.Entry<Integer, byte[]> e : data.entrySet()) {
      val = e.getValue();
      add = new byte[3 + val.length];
      add[0] = e.getKey().byteValue();
      byte[] l = Bytes.intToByte16Revers(val.length);
      add[1] = l[0];
      add[2] = l[1];
      System.arraycopy(val, 0, add, 3, val.length);
      lhi += add.length;
      r.add(add);
    }
    byte[] l = Bytes.intToByte16Revers(lhi);
    la[0] = l[0];
    la[1] = l[1];
    int s = 0;
    for (int i = 0; i < r.size(); i++) {
      s = updateCRC16msb(s, r.get(i));
    }
    s = ((s<<8) + (s>>8)) & 0xffff;
    byte[] crc = Bytes.intToByte16Revers(s);
    r.add(crc);
    return r;
  }
  private int updateCRC16msb(int s, int bb) {
    int b = bb;
    for(int j = 0 ; j < 8 ; j++) {
      int x16 = ((((b&0x80) > 0 && (s&0x8000) > 0))
          ||(((b&0x80) == 0) && ((s&0x8000) == 0))) ? 0 : 1;
      int x15 = ((((x16 == 1)&&(s&0x4000) > 0))
          ||((x16 == 0)&&((s&0x4000) == 0))) ? 0 : 1;
      int x2 = ((((x16 == 1)&&(s&0x0002) > 0))
          ||((x16 == 0)&&((s&0x0002) == 0))) ? 0 : 1;
      s = (s << 1) & 0xffff;
      b = (b << 1) & 0xffff;
      s |= (x16 == 1) ? 0x0001 : 0;
      s = (x2 == 1) ? s | 0x0004 : s & 0xfffb;
      s = (x15 == 1) ? s | 0x8000 : s & 0x7fff;
    }
    return s;
  }

  private int updateCRC16msb(int s, byte pBuf[]) {
    int lSize = pBuf.length;
    for(int i = 0; i < lSize; i++) {
      s = updateCRC16msb(s, pBuf[i] & 0xff);
    }
    return s;
  }

  public int getLengthMsg() {
    if (type != STX && type != SOH)
      return 0;
    return (((type == SOH) ? (header.size() * 3) + lenh + 2 : 0) // HEADER (NAME + LEN + D) * N + LENH
        + (data.size() * 3) + len // DATA (NAME + LEN + D) * N
        + 2 // LRC
    );
  }

  public int getLengthFull() {
    if (type != STX && type != SOH)
      return 1;
    return 1 // STX || SOH
        + 2 // LEN
        + getLengthMsg();
  }

  private void setField0(Integer key, byte[] val) {
    byte[] dta = data.remove(key);
    if (dta != null)
      len = len - dta.length;
    if (val != null) {
      data.put(key, val);
      len += val.length;
    }
  }

  private void setField0(Integer key, String val) throws SysException {
    byte[] v = null;
    if (val != null) {
      try {
        v = val.getBytes(charset);
      } catch (UnsupportedEncodingException e) {
        throw new SysException(e);
      }
    }
    byte[] dta = data.remove(key);
    if (dta != null)
      len = len - dta.length;
    if (v != null) {
      data.put(key, v);
      len += v.length;
    }
  }

  private void setFieldH0(Integer key, String val) throws SysException {
    byte[] v = null;
    if (val != null) {
      try {
        v = val.getBytes(charset);
      } catch (UnsupportedEncodingException e) {
        throw new SysException(e);
      }
    }
    byte[] dta = header.remove(key);
    if (dta != null)
      lenh = lenh - dta.length;
    if (v != null) {
      header.put(key, v);
      lenh += v.length;
    }
  }

  private void setFieldH0(Integer key, byte[] val){
    byte[] dta = header.remove(key);
    if (dta != null)
      lenh = lenh - dta.length;
    if (val != null) {
      header.put(key & 0xff, val);
      lenh += val.length;
    }
  }

  private final PrmInterface prms = new Prm();

  public PrmInterface getPrmInterface() throws SysException {
    return prms;
  }

  public class Prm implements PrmInterface {

    public void setField(String key, String val) throws SysException {
      if (key == null || key.length() == 0)
        return;
      if ("type".equals(key)) {
        byte type = (byte) (0xff & Strings.parseIntegerNvl(val, STX));
        if (type == STX || type == SOH ||
            type == EOT || type == ACK || type == CR || type == NAK || type == ENQ)
          SAMsg.this.type = type;
        else
          throw new SysException("The type of message is incorrect");
      } else if (key.substring(0, 1).equals("h"))
          setFieldH0(Integer.parseInt(key.substring(1)), val);
      else
        setField0(Integer.parseInt(key), val);
    }

    public String getField(String key) throws SysException {
      if (key == null || key.length() == 0)
        return null;
      byte[] dta;
      if ("type".equals(key)) {
        return String.valueOf(type);
      } else if (key.substring(0, 1).equals("h"))
        dta = header.get(Integer.valueOf(key.substring(1)));
      else
        dta = data.get(Integer.valueOf(key));
      if (dta == null)
        return null;
      try {
        return new String(dta, charset);
      } catch (UnsupportedEncodingException e) {
        throw new SysException(e);
      }
    }

    public byte[] getByteField(String key) throws SysException {
      if (key == null || key.length() == 0)
        return null;
      try {
        if ("type".equals(key)) {
          return String.valueOf(type).getBytes(charset);
        } else if (key.substring(0, 1).equals("h"))
          return header.get(Integer.valueOf(key.substring(1)));
      } catch (UnsupportedEncodingException e) {
        throw new SysException(e);
      }
      return data.get(key);
    }

    public void clearField(String key) throws SysException {
      setField(key, null);
    }

    public boolean isPresentField(String key) throws SysException {
      if (key == null || key.length() == 0)
        return false;
      if ("type".equals(key)) {
        return true;
      } else if (key.substring(0, 1).equals("h"))
        return header.get(Integer.valueOf(key.substring(1))) != null;
      return data.get(Integer.valueOf(key)) != null;
    }

    public void clearFields() throws SysException {
      len = 0;
      data.clear();
      lenh = 0;
      header.clear();
    }

    public StringList getFieldNames() {
      StringList sl = new StringList();
      sl.add("type");
      if (type == STX || type == SOH) {
        for (Integer k : data.keySet())
          sl.add(k.toString());
        if (type == SOH)
          for (Integer k : header.keySet())
            sl.add("h" + k);
      }
      return sl;
    }

  }

  public String getKey() throws SysException {
    return null;
  }

  public void setKey(String key) throws SysException {
  }

  public CloseableOutputStream getOutputStream() throws IOException {
    return new MessageOutputStream();
  }

  private static enum STEP {TYPE, MSG_LEN, HEADER_LEN, HEADER_FLD, FLD, CRC, NONE};
  private class MessageOutputStream extends CloseableOutputStream {
    private STEP step = STEP.TYPE;   // секция
    private int pos = 0; // позиция в секции
    private int fld;     // код поля
    private byte[] ln = new byte[2]; // буфер для длины
    private int lmsg = 0;// длина сообщения
    private int lhdr = 0;// длина заголовка
    private int lfld = 0;// длина поля
    private int crc = 0; // контроль
    private int ll = 0// номер записываемого символа
    private byte[] data = null; // буфер для значения поля
    public void write(int b) throws IOException {
      ll ++;
      if (b == -1 && !STEP.NONE.equals(step))
        throw new IOException("The stream isn't comleted (pos = " + ll + ")");
      if (STEP.NONE.equals(step)) // Если поток закрыт
        throw new IOException("The stream is already closed");
      if (STEP.TYPE.equals(step)) { // Type
        type = (byte) (b & 0xff);
        if (type == EOT || type == ACK || type == CR || type == NAK || type == ENQ) {
          step = STEP.NONE;
        } else if (type == STX || type == SOH) {
          step = STEP.MSG_LEN;
          pos = 0;
        } else
          throw new IOException("The type of message is incorrect");
        crc = updateCRC16msb(crc, type);
      } else if (STEP.MSG_LEN.equals(step)) {// msg's len
        ln[pos] = (byte) (b & 0xff);
        crc = updateCRC16msb(crc, b & 0xff);
        pos++;
        if (pos == 2) {
          lmsg = Bytes.byteToInt(ln);
          pos = 0;
          if (type == STX)
            step = STEP.FLD;
          else step = STEP.HEADER_LEN;
        }
      } else if (STEP.HEADER_LEN.equals(step)) {// header's len
        ln[pos] = (byte) (b & 0xff);
        crc = updateCRC16msb(crc, b & 0xff);
        pos++;
        if (pos == 2) {
          pos = 0;
          lhdr = Bytes.byteToInt(ln);
          if (lhdr == 0)
            step = STEP.FLD;
          else
            step = STEP.HEADER_FLD;
        }
      } else if (STEP.HEADER_FLD.equals(step)) {// Fields in header
        byte bt = (byte) (b & 0xff);
        crc = updateCRC16msb(crc, bt);
        switch (pos) {
        case 0: fld = bt;  pos++; break;
        case 1: ln[0] = bt;  pos++; break;
        case 2: ln[1] = bt;  lfld = Bytes.byteToInt(ln)
          if(lfld == 0) {
            lhdr -= 3;
            lmsg -= 3;
            pos = 0;
            if (lhdr == 0) {
              lmsg = lmsg - 2;
              if (lmsg > 0) step = STEP.FLD;
              else if (lmsg == 0) step = STEP.CRC;
              else throw new IOException("Incorrect message's length");
            }
          }
          else {
            pos++;
            data = new byte[lfld];
          }
          break;
        default:
          lfld--;
          data[pos-3] = bt;
          if(lfld == 0) {
            pos = 0;
            lhdr -= (data.length + 3);
            lmsg -= (data.length + 3);
            SAMsg.this.setFieldH0(fld, data);
            data = null;
            if (lhdr == 0) {
              step = STEP.FLD;
              lmsg = lmsg - 2;
            }
          }
          else pos++;
        }
      } else if(STEP.FLD.equals(step)) {
        byte bt = (byte) (b & 0xff);
        crc = updateCRC16msb(crc, bt);
        switch (pos) {
        case 0: fld = bt;  pos++; break;
        case 1: ln[0] = bt;  pos++; break;
        case 2: ln[1] = bt;  lfld = Bytes.byteToInt(ln)
          if(lfld == 0) {
            lmsg -= 3;
            pos = 0;
            if (lmsg == 0) step = STEP.CRC;
            else if (lmsg < 0) throw new IOException("Incorrect message's length");
          }
          else {
            pos++;
            data = new byte[lfld];
          }
          break;
        default:
          lfld--;
          data[pos-3] = bt;
          if(lfld == 0) {
            pos = 0;
            lmsg -= (data.length + 3);
            SAMsg.this.setField0(fld, data);
            data = null;
            if (lmsg < 0)
              throw new IOException("Incorrect message's lenght");
            if (lmsg == 0)
              step = STEP.CRC;
          }
          else pos++;
        }
      } else if(STEP.CRC.equals(step)) {
        ln[pos] = (byte) (b & 0xff);
        pos++;
        if (pos == 2) {
          int lcrc = ((crc<<8) + (crc>>8)) & 0xffff;
          if (lcrc != Bytes.byteToInt(ln))
            throw new IOException("Incorrect LRC (" + lcrc + " != " + crc + ")");
          step = STEP.NONE;
        }
      }
    }

    public void close() throws IOException {
      step = STEP.NONE;
    }

    public boolean isClosed() {
      return (STEP.NONE.equals(step));
    }
  }
}
TOP

Related Classes of center.system.msg.SAMsg$MessageOutputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.