1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #define __json_h__
8 #include <vector>
9 #include "gtest/gtest.h"
10 #include "nss_scoped_ptrs.h"
11 #include "pk11pub.h"
12 
13 // If we make a few assumptions about the file, parsing JSON can be easy.
14 // This is not a full parser, it only works on a narrow set of inputs.
15 class JsonReader {
16  public:
JsonReader(const std::string & n)17   JsonReader(const std::string &n) : buf_(), available_(0), i_(0) {
18     f_.reset(PR_Open(n.c_str(), PR_RDONLY, 00600));
19     EXPECT_TRUE(f_) << "error opening vectors from: " << n;
20     buf_[0] = 0;
21   }
22 
next()23   void next() { i_++; }
peek()24   uint8_t peek() {
25     TopUp();
26     return buf_[i_];
27   }
take()28   uint8_t take() {
29     uint8_t v = peek();
30     next();
31     return v;
32   }
33 
34   // No input checking, overflow protection, or any safety.
35   // Returns 0 if there isn't a number here rather than aborting.
ReadInt()36   uint64_t ReadInt() {
37     SkipWhitespace();
38     uint8_t c = peek();
39     uint64_t v = 0;
40     while (c >= '0' && c <= '9') {
41       v = v * 10 + c - '0';
42       next();
43       c = peek();
44     }
45     return v;
46   }
47 
48   // No input checking, no unicode, no escaping (not even \"), just read ASCII.
ReadString()49   std::string ReadString() {
50     SkipWhitespace();
51     if (peek() != '"') {
52       return "";
53     }
54     next();
55 
56     std::string s;
57     uint8_t c = take();
58     while (c != '"') {
59       s.push_back(c);
60       c = take();
61     }
62     return s;
63   }
64 
ReadLabel()65   std::string ReadLabel() {
66     std::string s = ReadString();
67     SkipWhitespace();
68     EXPECT_EQ(take(), ':');
69     return s;
70   }
71 
ReadHex()72   std::vector<uint8_t> ReadHex() {
73     SkipWhitespace();
74     uint8_t c = take();
75     EXPECT_EQ(c, '"');
76     std::vector<uint8_t> v;
77     c = take();
78     while (c != '"') {
79       v.push_back(JsonReader::Hex(c) << 4 | JsonReader::Hex(take()));
80       c = take();
81     }
82     return v;
83   }
84 
85   bool NextItem(uint8_t h = '{', uint8_t t = '}') {
86     SkipWhitespace();
87     switch (uint8_t c = take()) {
88       case ',':
89         return true;
90       case '{':
91       case '[':
92         EXPECT_EQ(c, h);
93         SkipWhitespace();
94         if (peek() == t) {
95           next();
96           return false;
97         }
98         return true;
99       case '}':
100       case ']':
101         EXPECT_EQ(c, t);
102         return false;
103       default:
104         ADD_FAILURE() << "Unexpected '" << c << "'";
105     }
106     return false;
107   }
108 
NextItemArray()109   bool NextItemArray() { return NextItem('[', ']'); }
110 
SkipValue()111   void SkipValue() {
112     uint8_t c = take();
113     if (c == '"') {
114       do {
115         c = take();
116       } while (c != '"');
117     } else if (c >= '0' && c <= '9') {
118       c = peek();
119       while (c >= '0' && c <= '9') {
120         next();
121         c = peek();
122       }
123     } else {
124       ADD_FAILURE() << "No idea how to skip'" << c << "'";
125     }
126   }
127 
128  private:
TopUp()129   void TopUp() {
130     if (available_ > i_) {
131       return;
132     }
133     i_ = 0;
134     if (!f_) {
135       return;
136     }
137     PRInt32 res = PR_Read(f_.get(), buf_, sizeof(buf_));
138     if (res > 0) {
139       available_ = static_cast<size_t>(res);
140     } else {
141       available_ = 1;
142       f_.reset(nullptr);
143       buf_[0] = 0;
144     }
145   }
146 
SkipWhitespace()147   void SkipWhitespace() {
148     uint8_t c = peek();
149     while (c && (c == ' ' || c == '\t' || c == '\r' || c == '\n')) {
150       next();
151       c = peek();
152     }
153   }
154 
155   // This only handles lowercase.
Hex(uint8_t c)156   uint8_t Hex(uint8_t c) {
157     if (c >= '0' && c <= '9') {
158       return c - '0';
159     }
160     EXPECT_TRUE(c >= 'a' && c <= 'f');
161     return c - 'a' + 10;
162   }
163 
164   ScopedPRFileDesc f_;
165   uint8_t buf_[4096];
166   size_t available_;
167   size_t i_;
168 };
169