001    package edu.harvard.deas.hyperenc;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import edu.harvard.deas.hyperenc.util.HexCoder;
007    import edu.harvard.deas.hyperenc.util.Pair;
008    
009    /**
010     * Parses plain-text representations of hyper-encryption protocol messages
011     * according to the following specification:
012     * <p>
013     * <b>Master reconciliation message</b>: Each line contains one ID-hash pair.
014     * The integer ID comes first, followed by a single space, followed by the hash,
015     * encoded as a hexadecimal number using digits 0-9 and a-f (case-insensitive).
016     * <p>
017     * <b>Slave reconciliation message</b>: Each line contains one ID-code pair. The
018     * integer ID comes first, followed by a single space, followed by a result
019     * code, which must be one of the following single-character strings:
020     * <ul>
021     * <li>"<b>+</b>" for SlaveRecResult.SUCCESS</li>
022     * <li>"<b>0</b>" for SlaveRecResult.NO_RESULT</li>
023     * <li>"<b>-</b>" for SlaveRecResult.FAILURE</li>
024     * </ul>
025     * @see SlaveRecResult
026     */
027    public class PlainTextMessageParser extends MessageParser {
028    
029      @Override
030      public List<Pair<Integer, byte[]>> parseMRec(String message)
031          throws MessageParseException {
032        List<Pair<Integer,byte[]>> result = new ArrayList<Pair<Integer,byte[]>>();
033        
034        String lines[] = message.split("\\r?\\n");
035        for (String line : lines) {
036          String tokens[] = line.split(" ", 2);
037          int id;
038          byte[] hash;
039          
040          try {
041            id = Integer.parseInt(tokens[0]);
042          } catch (NumberFormatException e) {
043            throw new MessageParseException(
044                "Illegal ID: " + tokens[0], message, e);
045          }
046          
047          try {
048            hash = HexCoder.decode(tokens[1].toLowerCase());
049          } catch (IllegalArgumentException e) {
050            throw new MessageParseException(
051                "Illegal hash string: " + tokens[1], message, e);
052          }
053          
054          result.add(new Pair<Integer,byte[]>(id, hash));
055        }
056        
057        return result;
058      }
059    
060      @Override
061      public List<Pair<Integer, SlaveRecResult>> parseSRec(String message)
062          throws MessageParseException {
063        List<Pair<Integer,SlaveRecResult>> result =
064          new ArrayList<Pair<Integer,SlaveRecResult>>();
065        
066        String lines[] = message.split("\\r?\\n");
067        for (String line : lines) {
068          String tokens[] = line.split(" ", 2);
069          int id;
070          SlaveRecResult res;
071          
072          try {
073            id = Integer.parseInt(tokens[0]);
074          } catch (NumberFormatException e) {
075            throw new MessageParseException(
076                "Illegal ID: " + tokens[0], message, e);
077          }
078          
079          if (tokens[1].equals("+"))
080            res = SlaveRecResult.SUCCESS;
081          else if (tokens[1].equals("0"))
082            res = SlaveRecResult.NO_RESULT;
083          else if (tokens[1].equals("-"))
084            res = SlaveRecResult.FAILURE;
085          else
086            throw new MessageParseException(
087                "Illegal result code: " + tokens[1], message);
088          
089          result.add(new Pair<Integer,SlaveRecResult>(id, res));
090        }
091        
092        return result;
093      }
094      
095      @Override
096      public String mrecToString(List<Pair<Integer, byte[]>> lst) {
097        String result = "";
098        
099        for (Pair<Integer,byte[]> p : lst) {
100          int id = p.first();
101          byte[] hash = p.second();
102          
103          String line = id + " " + HexCoder.encode(hash) + "\n";
104          result += line;
105        }
106        
107        return result;
108      }
109    
110      /**
111       * {@inheritDoc}
112       * @throws IllegalArgumentException
113       *         if a result in <code>lst</code> is not supported by this parser
114       */
115      @Override
116      public String srecToString(List<Pair<Integer, SlaveRecResult>> lst) {
117        String result = "";
118        
119        for (Pair<Integer,SlaveRecResult> p : lst) {
120          int id = p.first();
121          SlaveRecResult res = p.second();
122          String code;
123          
124          switch (res) {
125          case SUCCESS:
126            code = "+";  break;
127          case NO_RESULT:
128            code = "0";  break;
129          case FAILURE:
130            code = "-";  break;
131          default:
132            throw new IllegalArgumentException(
133                "Invalid result code " + res.toString());
134          }
135          
136          String line = id + " " + code + "\n";
137          result += line;
138        }
139        
140        return result;
141      }
142    
143    }