vfs: check userland buffers before reading them.
[haiku.git] / src / apps / haikudepot / server / StandardMetaDataJsonEventListener.cpp
blobdbdb5dda0dc1216ebec3b35fcd9942b671925075
1 /*
2 * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
6 #include "StandardMetaDataJsonEventListener.h"
8 #include "stdio.h"
10 #define KEY_CREATE_TIMESTAMP "createTimestamp"
11 #define KEY_DATA_MODIFIED_TIMESTAMP "dataModifiedTimestamp"
14 class SmdStackedEventListener : public BJsonEventListener {
15 public:
16 SmdStackedEventListener(
17 StandardMetaDataJsonEventListener*
18 mainListener,
19 SmdStackedEventListener* parent);
20 ~SmdStackedEventListener();
22 void HandleError(status_t status, int32 line,
23 const char* message);
24 void Complete();
26 status_t ErrorStatus();
28 SmdStackedEventListener*
29 Parent();
30 StandardMetaData*
31 MetaData();
33 protected:
34 void SetStackedListenerMainListener(
35 SmdStackedEventListener* stackedListener);
37 StandardMetaDataJsonEventListener*
38 fMainListener;
39 SmdStackedEventListener*
40 fParent;
44 class SmdStackedArrayEventListener : public SmdStackedEventListener {
45 public:
46 SmdStackedArrayEventListener(
47 StandardMetaDataJsonEventListener*
48 mainListener,
49 SmdStackedEventListener* parent);
50 ~SmdStackedArrayEventListener();
52 bool Handle(const BJsonEvent& event);
57 class SmdStackedObjectMessageEventListener : public SmdStackedEventListener {
58 public:
59 SmdStackedObjectMessageEventListener(
60 BStringList* jsonPathObjectNames,
61 StandardMetaDataJsonEventListener*
62 mainListener,
63 SmdStackedEventListener* parent);
64 ~SmdStackedObjectMessageEventListener();
66 bool Handle(const BJsonEvent& event);
68 private:
69 BStringList* fJsonPathObjectNames;
70 BString fNextItemName;
74 // #pragma mark - SmdStackedEventListener
76 SmdStackedEventListener::SmdStackedEventListener(
77 StandardMetaDataJsonEventListener* mainListener,
78 SmdStackedEventListener* parent)
80 fMainListener = mainListener;
81 fParent = parent;
85 SmdStackedEventListener::~SmdStackedEventListener()
90 void
91 SmdStackedEventListener::HandleError(status_t status, int32 line,
92 const char* message)
94 fMainListener->HandleError(status, line, message);
98 void
99 SmdStackedEventListener::Complete()
101 fMainListener->Complete();
105 status_t
106 SmdStackedEventListener::ErrorStatus()
108 return fMainListener->ErrorStatus();
112 StandardMetaData*
113 SmdStackedEventListener::MetaData()
115 return fMainListener->MetaData();
119 SmdStackedEventListener*
120 SmdStackedEventListener::Parent()
122 return fParent;
126 void
127 SmdStackedEventListener::SetStackedListenerMainListener(
128 SmdStackedEventListener* stackedListener)
130 fMainListener->SetStackedListener(stackedListener);
134 // #pragma mark - SmdStackedArrayEventListener
137 SmdStackedArrayEventListener::SmdStackedArrayEventListener(
138 StandardMetaDataJsonEventListener* mainListener,
139 SmdStackedEventListener* parent)
141 SmdStackedEventListener(mainListener, parent)
146 SmdStackedArrayEventListener::~SmdStackedArrayEventListener()
151 bool
152 SmdStackedArrayEventListener::Handle(const BJsonEvent& event)
154 if (ErrorStatus() != B_OK)
155 return false;
157 switch (event.EventType()) {
159 case B_JSON_NUMBER:
160 case B_JSON_STRING:
161 case B_JSON_TRUE:
162 case B_JSON_FALSE:
163 case B_JSON_NULL:
164 // ignore these atomic types in an array.
165 break;
167 case B_JSON_OBJECT_START:
168 SetStackedListenerMainListener(
169 new SmdStackedObjectMessageEventListener(NULL, fMainListener,
170 this));
171 break;
173 case B_JSON_ARRAY_START:
174 SetStackedListenerMainListener(new SmdStackedArrayEventListener(
175 fMainListener, this));
176 break;
178 case B_JSON_ARRAY_END:
179 SetStackedListenerMainListener(fParent);
180 delete this;
181 break;
183 case B_JSON_OBJECT_END:
184 case B_JSON_OBJECT_NAME:
185 HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
186 "illegal state when processing events in an array");
187 return false;
190 return true;
194 // #pragma mark - SmdStackedObjectMessageEventListener
196 SmdStackedObjectMessageEventListener::SmdStackedObjectMessageEventListener(
197 BStringList* jsonPathObjectNames,
198 StandardMetaDataJsonEventListener* mainListener,
199 SmdStackedEventListener* parent)
201 SmdStackedEventListener(mainListener, parent)
203 fJsonPathObjectNames = jsonPathObjectNames;
207 SmdStackedObjectMessageEventListener::~SmdStackedObjectMessageEventListener()
209 if (fJsonPathObjectNames != NULL)
210 delete fJsonPathObjectNames;
214 bool
215 SmdStackedObjectMessageEventListener::Handle(const BJsonEvent& event)
217 if (ErrorStatus() != B_OK)
218 return false;
220 switch (event.EventType()) {
222 case B_JSON_OBJECT_NAME:
223 fNextItemName = event.Content();
224 break;
226 case B_JSON_NUMBER:
227 if (fJsonPathObjectNames != NULL
228 && fJsonPathObjectNames->IsEmpty()) {
230 if (fNextItemName == KEY_CREATE_TIMESTAMP) {
231 MetaData()->SetCreateTimestamp(
232 event.ContentInteger());
235 if (fNextItemName == KEY_DATA_MODIFIED_TIMESTAMP) {
236 MetaData()->SetDataModifiedTimestamp(
237 event.ContentInteger());
240 break;
242 case B_JSON_STRING:
243 case B_JSON_TRUE:
244 case B_JSON_FALSE:
245 case B_JSON_NULL:
246 // ignore these atomic types as they are not required to fill the
247 // data structure.
248 break;
250 case B_JSON_OBJECT_START:
252 BStringList* nextJsonPathObjectNames = NULL;
254 // if this next object is on the path then remove it from the
255 // path and carry on down. If it's not on the path then just
256 // drop the path from the next object.
258 if (fJsonPathObjectNames != NULL
259 && !fJsonPathObjectNames->IsEmpty()
260 && fNextItemName == fJsonPathObjectNames->StringAt(0)) {
261 nextJsonPathObjectNames = new BStringList(*fJsonPathObjectNames);
262 nextJsonPathObjectNames->Remove(0);
265 SetStackedListenerMainListener(
266 new SmdStackedObjectMessageEventListener(nextJsonPathObjectNames,
267 fMainListener, this));
268 break;
271 case B_JSON_ARRAY_START:
272 SetStackedListenerMainListener(new SmdStackedArrayEventListener(
273 fMainListener, this));
274 break;
276 case B_JSON_OBJECT_END:
277 SetStackedListenerMainListener(fParent);
278 delete this;
279 break;
281 case B_JSON_ARRAY_END:
282 HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
283 "illegal state when processing events in an array");
284 return false;
287 return true;
291 // #pragma mark - StandardMetaDataJsonEventListener
294 StandardMetaDataJsonEventListener::StandardMetaDataJsonEventListener(
295 const BString& jsonPath,
296 StandardMetaData& metaData)
298 fMetaData = &metaData;
299 SetJsonPath(jsonPath);
300 fErrorStatus = B_OK;
301 fStackedListener = NULL;
305 StandardMetaDataJsonEventListener::~StandardMetaDataJsonEventListener()
307 if (fStackedListener != NULL)
308 delete fStackedListener;
312 void
313 StandardMetaDataJsonEventListener::SetJsonPath(const BString& jsonPath)
315 jsonPath.Split(".", true, fJsonPathObjectNames);
317 if (fJsonPathObjectNames.IsEmpty()) {
318 HandleError(B_BAD_VALUE, JSON_EVENT_LISTENER_ANY_LINE,
319 "json path required");
320 } else {
321 if (fJsonPathObjectNames.First() != "$") {
322 HandleError(B_BAD_VALUE, JSON_EVENT_LISTENER_ANY_LINE,
323 "illegal json path; should start with '$");
329 void
330 StandardMetaDataJsonEventListener::SetStackedListener(
331 SmdStackedEventListener *listener)
333 fStackedListener = listener;
337 bool
338 StandardMetaDataJsonEventListener::Handle(const BJsonEvent& event)
340 if (fErrorStatus != B_OK)
341 return false;
343 // best to exit early if the parsing has obtained all of the required
344 // data already.
346 if (fMetaData->IsPopulated())
347 return false;
349 if (fStackedListener != NULL)
350 return fStackedListener->Handle(event);
352 // the first thing that comes in must be an object container. It is
353 // bad data if it does not start with an object container.
355 switch (event.EventType()) {
357 case B_JSON_OBJECT_START:
359 BStringList* jsonPathObjectNames = new BStringList(
360 fJsonPathObjectNames);
361 jsonPathObjectNames->Remove(0);
363 SetStackedListener(
364 new SmdStackedObjectMessageEventListener(
365 jsonPathObjectNames, this, NULL)
368 break;
370 default:
371 HandleError(B_BAD_DATA, JSON_EVENT_LISTENER_ANY_LINE,
372 "the top level element must be an object");
373 return false;
377 return true;
381 void
382 StandardMetaDataJsonEventListener::HandleError(status_t status, int32 line,
383 const char* message)
385 fprintf(stderr, "an error has arisen processing the standard "
386 "meta data; %s\n", message);
387 fErrorStatus = status;
391 void
392 StandardMetaDataJsonEventListener::Complete()
397 status_t
398 StandardMetaDataJsonEventListener::ErrorStatus()
400 return fErrorStatus;
404 StandardMetaData*
405 StandardMetaDataJsonEventListener::MetaData()
407 return fMetaData;