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
30static int StringSize(const std::string &Str) {
31 //FIXME: Unicode
32 return (2 + Str.size() + 3) & ~3;
33}
34
35int 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
58static uint32_t ComputeHeader(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
73QBJS::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
122QBJS::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
131QBJS::Stream& QBJS::Stream::operator<<(uint32_t I)
132{
133 (*this) << uint16_t(I) << uint16_t(I>>16);
134 return *this;
135}
136
137QBJS::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
145QBJS::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
160bool 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