1 | /**************************************************************************** |
2 | * Copyright (C) 2013-2016 Woboq GmbH |
3 | * Olivier Goffart <contact at woboq.com> |
4 | * https://woboq.com/ |
5 | * |
6 | * This program is free software: you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation, either version 3 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "qbjs.h" |
21 | #include <llvm/Support/raw_ostream.h> |
22 | #include <llvm/Support/YAMLParser.h> |
23 | #include <llvm/Support/Casting.h> |
24 | #include <llvm/ADT/SmallVector.h> |
25 | #include <llvm/ADT/SmallString.h> |
26 | #include <llvm/ADT/Twine.h> |
27 | |
28 | #include <iostream> |
29 | |
30 | static int StringSize(const std::string &Str) { |
31 | //FIXME: Unicode |
32 | return (2 + Str.size() + 3) & ~3; |
33 | } |
34 | |
35 | int QBJS::Value::ComputeSize() const |
36 | { |
37 | int D = 0; |
38 | switch(T) { |
39 | case Undefined: return 0; |
40 | case Null: return 0; |
41 | case Bool: return 0; |
42 | case String: return StringSize(Str); |
43 | case Double: return 8; // FIXME: int optimisation |
44 | case Array: |
45 | for (const auto &E : Elems) D += E.Size() + 4; |
46 | return 12 + D; |
47 | case Object: |
48 | for (const auto &E : Props) { |
49 | D += StringSize(E.first); |
50 | D += E.second.Size() + 8; |
51 | } |
52 | return 12 + D; |
53 | default: |
54 | return -1; |
55 | } |
56 | } |
57 | |
58 | static uint32_t (const QBJS::Value &V, int Off) { |
59 | using namespace QBJS; |
60 | uint32_t H = V.T & 0x7; |
61 | if (V.T == String) |
62 | H |= 1<<3; // FIXME: Unicode |
63 | if (V.T == Bool) { |
64 | if (V.D > 0) |
65 | H |= 1 << 5; |
66 | } else { |
67 | H |= uint32_t(Off << 5); |
68 | } |
69 | return H; |
70 | } |
71 | |
72 | |
73 | QBJS::Stream& QBJS::Stream::operator<<(const QBJS::Value &V) |
74 | { |
75 | if (V.T == Undefined) |
76 | return *this; |
77 | else if (V.T == Object) { |
78 | llvm::SmallVector<uint32_t, 128> Table; |
79 | |
80 | (*this) << uint32_t(V.Size()); |
81 | (*this) << uint32_t(1 | V.Props.size() << 1); |
82 | (*this) << uint32_t(V.Size() - V.Props.size() * 4); |
83 | |
84 | uint32_t Off = 12; |
85 | for (auto E : V.Props) { |
86 | Table.push_back(Off); |
87 | Off += 4 + StringSize(E.first); |
88 | uint32_t H = ComputeHeader(E.second, Off); |
89 | H |= 1<<4; |
90 | (*this) << H << E.first << E.second; |
91 | Off += E.second.Size(); |
92 | } |
93 | for (uint32_t T : Table) |
94 | (*this) << T; |
95 | } else if (V.T == Array) { |
96 | llvm::SmallVector<uint32_t, 128> Table; |
97 | |
98 | (*this) << uint32_t(V.Size()); |
99 | (*this) << uint32_t(V.Elems.size() << 1); |
100 | (*this) << uint32_t(V.Size() - V.Elems.size() * 4); |
101 | |
102 | uint32_t Off = 12; |
103 | for (auto E : V.Elems) { |
104 | Table.push_back(ComputeHeader(E, Off)); |
105 | (*this) << E; |
106 | Off += E.Size(); |
107 | } |
108 | for (uint32_t T : Table) |
109 | (*this) << T; |
110 | } else if (V.T == Double) { |
111 | // Hum Hum: |
112 | uint64_t D; |
113 | memcpy(&D, &V.D, sizeof(double)); |
114 | (*this) << uint32_t(D & 0xffffffff); |
115 | (*this) << uint32_t(D >> 32); |
116 | } else if (V.T == String) { |
117 | (*this) << V.Str; |
118 | } |
119 | return *this; |
120 | } |
121 | |
122 | QBJS::Stream& QBJS::Stream::operator<<(const std::string &Str) |
123 | { |
124 | (*this) << uint16_t(Str.size()); |
125 | for (unsigned char S : Str) (*this) << S; |
126 | for (int I = Str.size() + 2; (I % 4)!=0 ;++I) |
127 | (*this) << (unsigned char)('\0'); //Padding; |
128 | return *this; |
129 | } |
130 | |
131 | QBJS::Stream& QBJS::Stream::operator<<(uint32_t I) |
132 | { |
133 | (*this) << uint16_t(I) << uint16_t(I>>16); |
134 | return *this; |
135 | } |
136 | |
137 | QBJS::Stream& QBJS::Stream::operator<<(uint16_t I) |
138 | { |
139 | typedef unsigned char uchar; |
140 | (*this) << uchar(I) << uchar(I>>8); |
141 | return *this; |
142 | |
143 | } |
144 | |
145 | QBJS::Stream& QBJS::Stream::operator<<(unsigned char C) |
146 | { |
147 | OS << "0x" ; |
148 | OS.write_hex(C); |
149 | OS << "," ; |
150 | Col++; |
151 | if (Col > 15) { |
152 | Col = 0; |
153 | OS << "\n " ; |
154 | } |
155 | OS << " " ; |
156 | return *this; |
157 | } |
158 | |
159 | |
160 | bool QBJS::Parse(llvm::yaml::Node* Node, QBJS::Value& Root) |
161 | { |
162 | if (!Node) return false; |
163 | if (llvm::yaml::SequenceNode *Array = llvm::dyn_cast<llvm::yaml::SequenceNode>(Node)) { |
164 | Root.T = QBJS::Array; |
165 | for (llvm::yaml::SequenceNode::iterator AI = Array->begin(), AE = Array->end(); |
166 | AI != AE; ++AI) { |
167 | Root.Elems.emplace_back(); |
168 | if (!Parse(AI, Root.Elems.back())) |
169 | return false; |
170 | } |
171 | return true; |
172 | } else if (llvm::yaml::MappingNode *Object = llvm::dyn_cast<llvm::yaml::MappingNode>(Node)) { |
173 | Root.T = QBJS::Object; |
174 | for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), KVE = Object->end(); |
175 | KVI != KVE; ++KVI) { |
176 | |
177 | llvm::yaml::ScalarNode *KeyString = llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey()); |
178 | if (!KeyString) |
179 | return false; |
180 | llvm::yaml::Node *Value = (*KVI).getValue(); |
181 | if (!Value) return false; |
182 | llvm::SmallString<20> Storage; |
183 | if (!Parse(Value, Root.Props[KeyString->getValue(Storage)])) |
184 | return false; |
185 | } |
186 | return true; |
187 | } else if (llvm::yaml::ScalarNode *Scal = llvm::dyn_cast<llvm::yaml::ScalarNode>(Node)) { |
188 | llvm::SmallString<20> Storage; |
189 | Root = std::string(Scal->getValue(Storage)); |
190 | // FIXME: integer |
191 | return true; |
192 | } else if (Node->getType() == llvm::yaml::Node::NK_Null) { |
193 | Root.T = Null; |
194 | return true; |
195 | } else { |
196 | return false; |
197 | } |
198 | } |
199 | |
200 | |
201 | |
202 | |
203 | |