Mercurial > projects > orange
comparison orange/serialization/archives/XMLArchive.d @ 24:55f0a9d5df8d experimental
First step in refactoring the API.
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Tue, 05 Oct 2010 21:59:46 +0200 |
parents | 963b756ed579 |
children | b51e953f79eb |
comparison
equal
deleted
inserted
replaced
23:947c32ec0ea7 | 24:55f0a9d5df8d |
---|---|
14 | 14 |
15 import orange.serialization.archives._; | 15 import orange.serialization.archives._; |
16 import orange.util._; | 16 import orange.util._; |
17 import orange.xml.XMLDocument; | 17 import orange.xml.XMLDocument; |
18 | 18 |
19 private enum ArchiveMode | 19 final class XMLArchive (U = char) : Archive!(U) |
20 { | 20 { |
21 archiving, | |
22 unarchiving | |
23 } | |
24 | |
25 class XMLArchive (U = char) : Archive!(U) | |
26 { | |
27 static assert (isChar!(U), format!(`The given type "`, U, `" is not a valid type. Valid types are: "char", "wchar" and "dchar".`)); | |
28 | |
29 private struct Tags | 21 private struct Tags |
30 { | 22 { |
31 static const DataType structTag = "struct"; | 23 static const DataType structTag = "struct"; |
32 static const DataType dataTag = "data"; | 24 static const DataType dataTag = "data"; |
33 static const DataType archiveTag = "archive"; | 25 static const DataType archiveTag = "archive"; |
57 static const DataType offsetAttribute = "offset"; | 49 static const DataType offsetAttribute = "offset"; |
58 } | 50 } |
59 | 51 |
60 private | 52 private |
61 { | 53 { |
62 struct ArrayNode | |
63 { | |
64 XMLDocument!(U).Node parent; | |
65 XMLDocument!(U).Node node; | |
66 DataType id; | |
67 DataType key; | |
68 } | |
69 | |
70 struct Array | |
71 { | |
72 void* ptr; | |
73 size_t length; | |
74 size_t elementSize; | |
75 | |
76 static Array opCall (T) (T[] value) | |
77 { | |
78 Array array; | |
79 array.ptr = value.ptr; | |
80 array.length = value.length; | |
81 array.elementSize = T.sizeof; | |
82 | |
83 return array; | |
84 } | |
85 | |
86 bool isSliceOf (Array b) | |
87 { | |
88 return ptr >= b.ptr && ptr + length * elementSize <= b.ptr + b.length * b.elementSize; | |
89 } | |
90 } | |
91 | |
92 struct Slice | |
93 { | |
94 size_t length; | |
95 size_t offset; | |
96 DataType id; | |
97 } | |
98 | |
99 DataType archiveType = "org.dsource.orange.xml"; | 54 DataType archiveType = "org.dsource.orange.xml"; |
100 DataType archiveVersion = "0.1"; | 55 DataType archiveVersion = "0.1"; |
101 | 56 |
102 XMLDocument!(U) doc; | 57 XMLDocument!(U) doc; |
103 doc.Node lastElement; | 58 doc.Node lastElement; |
104 //DocPrinter!(U) printer; | |
105 doc.Node lastElementSaved; | |
106 | 59 |
107 bool hasBegunArchiving; | 60 bool hasBegunArchiving; |
108 bool hasBegunUnarchiving; | 61 bool hasBegunUnarchiving; |
109 | 62 |
110 DataType[void*] archivedReferences; | |
111 void*[DataType] unarchivedReferences; | |
112 | |
113 ArrayNode[Array] arraysToBeArchived; | 63 ArrayNode[Array] arraysToBeArchived; |
114 void[][DataType] unarchivedSlices; | 64 void[][DataType] unarchivedSlices; |
115 | 65 } |
116 size_t idCounter; | 66 |
117 } | 67 this (ErrorCallback errorCallback) |
118 | 68 { |
119 this () | 69 this.errorCallback = errorCallback; |
120 { | |
121 doc = new XMLDocument!(U); | 70 doc = new XMLDocument!(U); |
122 } | 71 } |
123 | 72 |
124 public void beginArchiving () | 73 public void beginArchiving () |
125 { | 74 { |
133 | 82 |
134 hasBegunArchiving = true; | 83 hasBegunArchiving = true; |
135 } | 84 } |
136 } | 85 } |
137 | 86 |
138 public void beginUnarchiving (DataType data) | 87 public void beginUnarchiving (IDataType untypedData) |
139 { | 88 { |
89 auto data = cast(DataType) untypedData; | |
90 | |
140 if (!hasBegunUnarchiving) | 91 if (!hasBegunUnarchiving) |
141 { | 92 { |
142 doc.parse(data); | 93 doc.parse(data); |
143 hasBegunUnarchiving = true; | 94 hasBegunUnarchiving = true; |
144 | 95 |
159 } | 110 } |
160 } | 111 } |
161 } | 112 } |
162 } | 113 } |
163 | 114 |
164 public DataType data () | 115 IDataType data () |
165 { | 116 { |
166 /*if (!printer) | |
167 printer = new DocPrinter!(U); | |
168 | |
169 return printer.print(doc);*/ | |
170 | |
171 return doc.toString(); | 117 return doc.toString(); |
172 } | 118 } |
173 | 119 |
174 public void reset () | 120 void postProcess () |
175 { | |
176 hasBegunArchiving = false; | |
177 hasBegunUnarchiving = false; | |
178 idCounter = 0; | |
179 doc.reset; | |
180 } | |
181 | |
182 private void begin () | |
183 { | |
184 lastElementSaved = lastElement; | |
185 } | |
186 | |
187 private void end () | |
188 { | |
189 lastElement = lastElementSaved; | |
190 } | |
191 | |
192 public void archive (T) (T value, DataType key, void delegate () dg = null) | |
193 { | |
194 if (!hasBegunArchiving) | |
195 beginArchiving(); | |
196 | |
197 restore(lastElement) in { | |
198 bool callDelegate = true; | |
199 | |
200 static if (isTypeDef!(T)) | |
201 archiveTypeDef(value, key); | |
202 | |
203 else static if (isObject!(T)) | |
204 archiveObject(value, key, callDelegate); | |
205 | |
206 else static if (isStruct!(T)) | |
207 archiveStruct(value, key); | |
208 | |
209 else static if (isString!(T)) | |
210 archiveString(value, key); | |
211 | |
212 else static if (isArray!(T)) | |
213 archiveArray(value, key); | |
214 | |
215 else static if (isAssociativeArray!(T)) | |
216 archiveAssociativeArray(value, key); | |
217 | |
218 else static if (isPrimitive!(T)) | |
219 archivePrimitive(value, key); | |
220 | |
221 else static if (isPointer!(T)) | |
222 archivePointer(value, key, callDelegate); | |
223 | |
224 else static if (isEnum!(T)) | |
225 archiveEnum(value, key); | |
226 | |
227 else | |
228 static assert(false, format!(`The type "`, T, `" cannot be archived.`)); | |
229 | |
230 if (callDelegate && dg) | |
231 dg(); | |
232 }; | |
233 } | |
234 | |
235 private void archiveObject (T) (T value, DataType key, ref bool callDelegate) | |
236 { | |
237 if (!value) | |
238 { | |
239 lastElement.element(Tags.nullTag) | |
240 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
241 .attribute(Attributes.keyAttribute, key); | |
242 callDelegate = false; | |
243 } | |
244 | |
245 else if (auto reference = getArchivedReference(value)) | |
246 { | |
247 archiveReference(key, reference); | |
248 callDelegate = false; | |
249 } | |
250 | |
251 else | |
252 { | |
253 DataType id = nextId; | |
254 | |
255 lastElement = lastElement.element(Tags.objectTag) | |
256 .attribute(Attributes.runtimeTypeAttribute, toDataType(value.classinfo.name)) | |
257 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
258 .attribute(Attributes.keyAttribute, key) | |
259 .attribute(Attributes.idAttribute, id); | |
260 | |
261 addArchivedReference(value, id); | |
262 } | |
263 } | |
264 | |
265 private void archiveStruct (T) (T value, DataType key) | |
266 { | |
267 lastElement = lastElement.element(Tags.structTag) | |
268 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
269 .attribute(Attributes.keyAttribute, key); | |
270 } | |
271 | |
272 private void archiveString (T) (T value, DataType key) | |
273 { | |
274 archiveArrayImpl(value, key, Tags.stringTag, toDataType(value)); | |
275 } | |
276 | |
277 private void archiveArray (T) (T value, DataType key) | |
278 { | |
279 archiveArrayImpl(value, key, Tags.arrayTag); | |
280 } | |
281 | |
282 private void archiveArrayImpl (T) (T value, DataType key, DataType tag, DataType content = null) | |
283 { | |
284 DataType id = nextId; | |
285 auto parent = lastElement; | |
286 | |
287 if (value.length == 0) | |
288 lastElement = lastElement.element(tag); | |
289 | |
290 else | |
291 lastElement = doc.createNode(tag, content); | |
292 | |
293 lastElement.attribute(Attributes.typeAttribute, toDataType(BaseTypeOfArray!(T).stringof)) | |
294 .attribute(Attributes.lengthAttribute, toDataType(value.length)) | |
295 .attribute(Attributes.keyAttribute, key) | |
296 .attribute(Attributes.idAttribute, id); | |
297 | |
298 arraysToBeArchived[Array(value)] = ArrayNode(parent, lastElement, id, key); | |
299 } | |
300 | |
301 private void archiveAssociativeArray (T) (T value, DataType key) | |
302 { | |
303 lastElement = lastElement.element(Tags.associativeArrayTag) | |
304 .attribute(Attributes.keyTypeAttribute, toDataType(KeyTypeOfAssociativeArray!(T).stringof)) | |
305 .attribute(Attributes.valueTypeAttribute, toDataType(ValueTypeOfAssociativeArray!(T).stringof)) | |
306 .attribute(Attributes.lengthAttribute, toDataType(value.length)) | |
307 .attribute(Attributes.keyAttribute, key); | |
308 } | |
309 | |
310 private void archivePointer (T) (T value, DataType key, ref bool callDelegate) | |
311 { | |
312 if (auto reference = getArchivedReference(value)) | |
313 { | |
314 archiveReference(key, reference); | |
315 callDelegate = false; | |
316 } | |
317 | |
318 else | |
319 { | |
320 DataType id = nextId; | |
321 | |
322 lastElement = lastElement.element(Tags.pointerTag) | |
323 .attribute(Attributes.keyAttribute, key) | |
324 .attribute(Attributes.idAttribute, id); | |
325 | |
326 addArchivedReference(value, id); | |
327 } | |
328 } | |
329 | |
330 private void archiveEnum (T) (T value, DataType key) | |
331 { | |
332 lastElement.element(Tags.enumTag, toDataType(value)) | |
333 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
334 .attribute(Attributes.keyAttribute, key); | |
335 } | |
336 | |
337 private void archivePrimitive (T) (T value, DataType key) | |
338 { | |
339 lastElement.element(toDataType(T.stringof), toDataType(value)) | |
340 .attribute(Attributes.keyAttribute, key); | |
341 } | |
342 | |
343 private void archiveTypeDef (T) (T value, DataType key) | |
344 { | |
345 lastElement = lastElement.element(Tags.typedefTag) | |
346 .attribute(Attributes.typeAttribute, toDataType(BaseTypeOfTypeDef!(T).stringof)); | |
347 .attribute(Attributes.key, key); | |
348 } | |
349 | |
350 public T unarchive (T) (DataType key, T delegate (T) dg = null) | |
351 { | |
352 if (!hasBegunUnarchiving) | |
353 beginUnarchiving(data); | |
354 | |
355 return restore!(T)(lastElement) in { | |
356 T value; | |
357 | |
358 bool callDelegate = true; | |
359 | |
360 static if (isTypeDef!(T)) | |
361 value = unarchiveTypeDef!(T)(key); | |
362 | |
363 else static if (isObject!(T)) | |
364 value = unarchiveObject!(T)(key, callDelegate); | |
365 | |
366 else static if (isStruct!(T)) | |
367 value = unarchiveStruct!(T)(key); | |
368 | |
369 else static if (isString!(T)) | |
370 value = unarchiveString!(T)(key); | |
371 | |
372 else static if (isArray!(T)) | |
373 value = unarchiveArray!(T)(key, callDelegate); | |
374 | |
375 else static if (isAssociativeArray!(T)) | |
376 value = unarchiveAssociativeArray!(T)(key); | |
377 | |
378 else static if (isPrimitive!(T)) | |
379 value = unarchivePrimitive!(T)(key); | |
380 | |
381 else static if (isPointer!(T)) | |
382 value = unarchivePointer!(T)(key, callDelegate); | |
383 | |
384 else static if (isEnum!(T)) | |
385 value = unarchiveEnum!(T)(key); | |
386 | |
387 else | |
388 static assert(false, format!(`The type "`, T, `" cannot be unarchived.`)); | |
389 | |
390 if (callDelegate && dg) | |
391 return dg(value); | |
392 | |
393 return value; | |
394 }; | |
395 } | |
396 | |
397 private T unarchiveObject (T) (DataType key, ref bool callDelegate) | |
398 { | |
399 DataType id = unarchiveReference(key); | |
400 | |
401 if (auto reference = getUnarchivedReference!(T)(id)) | |
402 { | |
403 callDelegate = false; | |
404 return *reference; | |
405 } | |
406 | |
407 auto tmp = getElement(Tags.objectTag, key, Attributes.keyAttribute, false); | |
408 | |
409 if (!tmp.isValid) | |
410 { | |
411 lastElement = getElement(Tags.nullTag, key); | |
412 callDelegate = false; | |
413 return null; | |
414 } | |
415 | |
416 lastElement = tmp; | |
417 | |
418 auto runtimeType = getValueOfAttribute(Attributes.runtimeTypeAttribute); | |
419 | |
420 if (!runtimeType) | |
421 return T.init; | |
422 | |
423 auto name = fromDataType!(string)(runtimeType); | |
424 id = getValueOfAttribute(Attributes.idAttribute); | |
425 | |
426 if (!id) | |
427 return T.init; | |
428 | |
429 T result = cast(T) newInstance(name); | |
430 | |
431 addUnarchivedReference(result, id); | |
432 | |
433 return result; | |
434 } | |
435 | |
436 private T unarchiveStruct (T) (DataType key) | |
437 { | |
438 auto element = getElement(Tags.structTag, key); | |
439 | |
440 if (element.isValid) | |
441 lastElement = element; | |
442 | |
443 return T.init; | |
444 } | |
445 | |
446 private T unarchiveString (T) (DataType key) | |
447 { | |
448 auto slice = unarchiveSlice(key); | |
449 | |
450 if (auto tmp = getUnarchivedSlice!(T)(slice)) | |
451 return *tmp; | |
452 | |
453 auto element = getElement(Tags.stringTag, key); | |
454 | |
455 if (!element.isValid) | |
456 return T.init; | |
457 | |
458 auto value = fromDataType!(T)(element.value); | |
459 slice.id = getValueOfAttribute(Attributes.idAttribute, element); | |
460 | |
461 if (!slice.id) | |
462 return T.init; | |
463 | |
464 addUnarchivedSlice(value, slice.id); | |
465 | |
466 return value; | |
467 } | |
468 | |
469 private T unarchiveArray (T) (DataType key, ref bool callDelegate) | |
470 { | |
471 auto slice = unarchiveSlice(key); | |
472 | |
473 if (auto tmp = getUnarchivedSlice!(T)(slice)) | |
474 { | |
475 callDelegate = false; | |
476 return *tmp; | |
477 } | |
478 | |
479 T value; | |
480 | |
481 auto element = getElement(Tags.arrayTag, key); | |
482 | |
483 if (!element.isValid) | |
484 return T.init; | |
485 | |
486 lastElement = element; | |
487 auto length = getValueOfAttribute(Attributes.lengthAttribute); | |
488 | |
489 if (!length) | |
490 return T.init; | |
491 | |
492 value.length = fromDataType!(size_t)(length); | |
493 slice.id = getValueOfAttribute(Attributes.idAttribute); | |
494 | |
495 if (!slice.id) | |
496 return T.init; | |
497 | |
498 addUnarchivedSlice(value, slice.id); | |
499 | |
500 return value; | |
501 } | |
502 | |
503 private T unarchiveAssociativeArray (T) (DataType key) | |
504 { | |
505 auto element = getElement(Tags.associativeArrayTag, key); | |
506 | |
507 if (element.isValid) | |
508 lastElement = element; | |
509 | |
510 return T.init; | |
511 } | |
512 | |
513 private T unarchivePointer (T) (DataType key, ref bool callDelegate) | |
514 { | |
515 DataType id = unarchiveReference(key); | |
516 | |
517 if (auto reference = getUnarchivedReference!(T)(id)) | |
518 { | |
519 callDelegate = false; | |
520 return *reference; | |
521 } | |
522 | |
523 auto element = getElement(Tags.pointerTag, key); | |
524 | |
525 if (!element.isValid) | |
526 return T.init; | |
527 | |
528 lastElement = element; | |
529 id = getValueOfAttribute(Attributes.idAttribute); | |
530 | |
531 if (!id) | |
532 return T.init; | |
533 | |
534 T result = new BaseTypeOfPointer!(T); | |
535 | |
536 addUnarchivedReference(result, id); | |
537 | |
538 return result; | |
539 } | |
540 | |
541 private T unarchiveEnum (T) (DataType key) | |
542 { | |
543 auto element = getElement(Tags.enumTag, key); | |
544 | |
545 if (!element.isValid) | |
546 return T.init; | |
547 | |
548 return fromDataType!(T)(element.value); | |
549 } | |
550 | |
551 private T unarchivePrimitive (T) (DataType key) | |
552 { | |
553 auto element = getElement(toDataType(T.stringof), key); | |
554 | |
555 if (!element.isValid) | |
556 return T.init; | |
557 | |
558 return fromDataType!(T)(element.value); | |
559 } | |
560 | |
561 private T unarchiveTypeDef (T) (DataType key) | |
562 { | |
563 auto element = getElement(Tags.typedefTag, key); | |
564 | |
565 if (element.isValid) | |
566 lastElement = element; | |
567 | |
568 return T.init; | |
569 } | |
570 | |
571 public AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T)) unarchiveAssociativeArrayVisitor (T) () | |
572 { | |
573 return AssociativeArrayVisitor!(KeyTypeOfAssociativeArray!(T), ValueTypeOfAssociativeArray!(T))(this); | |
574 } | |
575 | |
576 public void archiveBaseClass (T : Object) (DataType key) | |
577 { | |
578 lastElement = lastElement.element(Tags.baseTag) | |
579 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
580 .attribute(Attributes.keyAttribute, key); | |
581 } | |
582 | |
583 public void unarchiveBaseClass (T : Object) (DataType key) | |
584 { | |
585 auto element = getElement(Tags.baseTag, key); | |
586 | |
587 if (element.isValid) | |
588 lastElement = element; | |
589 } | |
590 | |
591 version (Tango) | |
592 { | |
593 template errorMessage (ArchiveMode mode = ArchiveMode.archiving) | |
594 { | |
595 static if (mode == ArchiveMode.archiving) | |
596 const errorMessage = "Could not continue archiving due to unrecognized data format: "; | |
597 | |
598 else static if (mode == ArchiveMode.unarchiving) | |
599 const errorMessage = "Could not continue unarchiving due to unrecognized data format: "; | |
600 } | |
601 } | |
602 | |
603 else | |
604 { | |
605 mixin( | |
606 `template errorMessage (ArchiveMode mode = ArchiveMode.archiving) | |
607 { | |
608 static if (mode == ArchiveMode.archiving) | |
609 enum errorMessage = "Could not continue archiving due to unrecognized data format: "; | |
610 | |
611 else static if (mode == ArchiveMode.unarchiving) | |
612 enum errorMessage = "Could not continue unarchiving due to unrecognized data format: "; | |
613 }` | |
614 ); | |
615 } | |
616 | |
617 private doc.Node getElement (DataType tag, DataType key, DataType attribute = Attributes.keyAttribute, bool throwOnError = true) | |
618 { | |
619 auto set = lastElement.query[tag].attribute((doc.Node node) { | |
620 if (node.name == attribute && node.value == key) | |
621 return true; | |
622 | |
623 return false; | |
624 }); | |
625 | |
626 if (set.nodes.length == 1) | |
627 return set.nodes[0].parent; | |
628 | |
629 else | |
630 { | |
631 if (throwOnError && errorCallback) | |
632 { | |
633 if (set.nodes.length == 0) | |
634 errorCallback(new ArchiveException(`Could not find an element "` ~ to!(string)(tag) ~ `" with the attribute "` ~ to!(string)(Attributes.keyAttribute) ~ `" with the value "` ~ to!(string)(key) ~ `".`, __FILE__, __LINE__), [tag, Attributes.keyAttribute, key]); | |
635 | |
636 else | |
637 errorCallback(new ArchiveException(`Could not unarchive the value with the key "` ~ to!(string)(key) ~ `" due to malformed data.`, __FILE__, __LINE__), [tag, Attributes.keyAttribute, key]); | |
638 } | |
639 | |
640 return doc.Node.invalid; | |
641 } | |
642 } | |
643 | |
644 private DataType getValueOfAttribute (DataType attribute, doc.Node element = doc.Node.invalid) | |
645 { | |
646 if (!element.isValid) element = lastElement; | |
647 | |
648 auto set = element.query.attribute(attribute); | |
649 | |
650 if (set.nodes.length == 1) | |
651 return set.nodes[0].value; | |
652 | |
653 else | |
654 { | |
655 if (errorCallback) | |
656 { | |
657 if (set.nodes.length == 0) | |
658 errorCallback(new ArchiveException(`Could not find the attribute "` ~ to!(string)(attribute) ~ `".`, __FILE__, __LINE__), [attribute]); | |
659 | |
660 else | |
661 errorCallback(new ArchiveException(`Could not unarchive the value of the attribute "` ~ to!(string)(attribute) ~ `" due to malformed data.`, __FILE__, __LINE__), [attribute]); | |
662 } | |
663 } | |
664 | |
665 return null; | |
666 } | |
667 | |
668 private void addArchivedReference (T) (T value, DataType id) | |
669 { | |
670 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); | |
671 | |
672 archivedReferences[cast(void*) value] = id; | |
673 } | |
674 | |
675 private void addUnarchivedReference (T) (T value, DataType id) | |
676 { | |
677 static assert(isReference!(T), format!(`The given type "`, T, `" is not a reference type, i.e. object or pointer.`)); | |
678 | |
679 unarchivedReferences[id] = cast(void*) value; | |
680 } | |
681 | |
682 private void addUnarchivedSlice (T) (T value, DataType id) | |
683 { | |
684 static assert(isArray!(T) || isString!(T), format!(`The given type "`, T, `" is not a slice type, i.e. array or string.`)); | |
685 | |
686 unarchivedSlices[id] = value; | |
687 } | |
688 | |
689 private DataType getArchivedReference (T) (T value) | |
690 { | |
691 if (auto tmp = cast(void*) value in archivedReferences) | |
692 return *tmp; | |
693 | |
694 return null; | |
695 } | |
696 | |
697 private T* getUnarchivedReference (T) (DataType id) | |
698 { | |
699 if (auto reference = id in unarchivedReferences) | |
700 return cast(T*) reference; | |
701 | |
702 return null; | |
703 } | |
704 | |
705 private T* getUnarchivedSlice (T) (Slice slice) | |
706 { | |
707 if (auto array = slice.id in unarchivedSlices) | |
708 return &(cast(T) *array)[slice.offset .. slice.length + 1]; // dereference the array, cast it to the right type, | |
709 // slice it and then return a pointer to the result | |
710 return null; | |
711 } | |
712 | |
713 private DataType nextId () | |
714 { | |
715 return toDataType(idCounter++); | |
716 } | |
717 | |
718 private void archiveReference (DataType key, DataType id) | |
719 { | |
720 lastElement.element(Tags.referenceTag, id) | |
721 .attribute(Attributes.keyAttribute, key); | |
722 } | |
723 | |
724 private DataType unarchiveReference (DataType key) | |
725 { | |
726 auto element = getElement(Tags.referenceTag, key, Attributes.keyAttribute, false); | |
727 | |
728 if (element.isValid) | |
729 return element.value; | |
730 | |
731 return cast(DataType) null; | |
732 } | |
733 | |
734 private Slice unarchiveSlice (DataType key) | |
735 { | |
736 auto element = getElement(Tags.sliceTag, key, Attributes.keyAttribute, false); | |
737 | |
738 if (element.isValid) | |
739 { | |
740 auto length = fromDataType!(size_t)(getValueOfAttribute(Attributes.lengthAttribute, element)); | |
741 auto offset = fromDataType!(size_t)(getValueOfAttribute(Attributes.offsetAttribute, element)); | |
742 | |
743 return Slice(length, offset, element.value); | |
744 } | |
745 | |
746 return Slice.init; | |
747 } | |
748 | |
749 private struct AssociativeArrayVisitor (Key, Value) | |
750 { | |
751 private XMLArchive archive; | |
752 | |
753 static AssociativeArrayVisitor opCall (XMLArchive archive) | |
754 { | |
755 AssociativeArrayVisitor aai; | |
756 aai.archive = archive; | |
757 | |
758 return aai; | |
759 } | |
760 | |
761 int opApply(int delegate(ref Key, ref Value) dg) | |
762 { | |
763 int result; | |
764 | |
765 foreach (node ; archive.lastElement.children) | |
766 { | |
767 restore(archive.lastElement) in { | |
768 archive.lastElement = node; | |
769 | |
770 if (node.attributes.exist) | |
771 { | |
772 Key key = to!(Key)(archive.getValueOfAttribute(Attributes.keyAttribute)); | |
773 Value value = to!(Value)(node.value); | |
774 | |
775 result = dg(key, value); | |
776 } | |
777 }; | |
778 | |
779 if (result) | |
780 break; | |
781 } | |
782 | |
783 return result; | |
784 } | |
785 } | |
786 | |
787 public void postProcess () | |
788 { | 121 { |
789 bool foundSlice = true; | 122 bool foundSlice = true; |
790 | 123 |
791 foreach (slice, sliceNode ; arraysToBeArchived) | 124 foreach (slice, sliceNode ; arraysToBeArchived) |
792 { | 125 { |
808 } | 141 } |
809 | 142 |
810 if (!foundSlice) | 143 if (!foundSlice) |
811 sliceNode.parent.attach(sliceNode.node); | 144 sliceNode.parent.attach(sliceNode.node); |
812 } | 145 } |
146 } | |
147 | |
148 void reset () | |
149 { | |
150 hasBegunArchiving = false; | |
151 hasBegunUnarchiving = false; | |
152 doc.reset; | |
153 } | |
154 | |
155 void archiveArray (Array array, string type, string key, size_t id) | |
156 { | |
157 internalArchiveArray(type, array, key, id, Tags.arrayTag); | |
158 } | |
159 | |
160 private void internalArchiveArray(string type, Array array, string key, size_t id, DataType tag, DataType content = null) | |
161 { | |
162 auto parent = lastElement; | |
163 | |
164 if (value.length == 0) | |
165 lastElement = lastElement.element(tag); | |
166 | |
167 else | |
168 lastElement = doc.createNode(tag, content); | |
169 | |
170 lastElement.attribute(Attributes.typeAttribute, toDataType(type)) | |
171 .attribute(Attributes.lengthAttribute, toDataType(length)) | |
172 .attribute(Attributes.keyAttribute, toDataType(key)) | |
173 .attribute(Attributes.idAttribute, toDataType(id)); | |
174 } | |
175 | |
176 void archiveAssociativeArray (string keyType, string valueType, size_t length, string key, size_t id) | |
177 { | |
178 lastElement = lastElement.element(Tags.associativeArrayTag) | |
179 .attribute(Attributes.keyTypeAttribute, toDataType(keyType)) | |
180 .attribute(Attributes.valueTypeAttribute, toDataType(valueType)) | |
181 .attribute(Attributes.lengthAttribute, toDataType(length)) | |
182 .attribute(Attributes.keyAttribute, key); | |
183 } | |
184 | |
185 void archiveEnum (bool value, string key, size_t id) | |
186 { | |
187 internalArchiveEnum(value, key, id); | |
188 } | |
189 | |
190 void archiveEnum (byte value, string key, size_t id) | |
191 { | |
192 internalArchiveEnum(value, key, id); | |
193 } | |
194 | |
195 void archiveEnum (char value, string key, size_t id) | |
196 { | |
197 internalArchiveEnum(value, key, id); | |
198 } | |
199 | |
200 void archiveEnum (dchar value, string key, size_t id) | |
201 { | |
202 internalArchiveEnum(value, key, id); | |
203 } | |
204 | |
205 void archiveEnum (int value, string key, size_t id) | |
206 { | |
207 internalArchiveEnum(value, key, id); | |
208 } | |
209 | |
210 void archiveEnum (long value, string key, size_t id) | |
211 { | |
212 internalArchiveEnum(value, key, id); | |
213 } | |
214 | |
215 void archiveEnum (short value, string key, size_t id) | |
216 { | |
217 internalArchiveEnum(value, key, id); | |
218 } | |
219 | |
220 void archiveEnum (ubyte value, string key, size_t id) | |
221 { | |
222 internalArchiveEnum(value, key, id); | |
223 } | |
224 | |
225 void archiveEnum (uint value, string key, size_t id) | |
226 { | |
227 internalArchiveEnum(value, key, id); | |
228 } | |
229 | |
230 void archiveEnum (ulong value, string key, size_t id) | |
231 { | |
232 internalArchiveEnum(value, key, id); | |
233 } | |
234 | |
235 void archiveEnum (ushort value, string key, size_t id) | |
236 { | |
237 internalArchiveEnum(value, key, id); | |
238 } | |
239 | |
240 void archiveEnum (wchar value, string key, size_t id) | |
241 { | |
242 internalArchiveEnum(value, key, id); | |
243 } | |
244 | |
245 private void internalArchiveEnum (T) (T value, string key, size_t id) | |
246 { | |
247 lastElement.element(Tags.enumTag, toDataType(value)) | |
248 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
249 .attribute(Attributes.keyAttribute, toDataType(key)); | |
250 } | |
251 | |
252 void archiveNull (string type, string key) | |
253 { | |
254 lastElement.element(Tags.nullTag) | |
255 .attribute(Attributes.typeAttribute, toDataType(T.stringof)) | |
256 .attribute(Attributes.keyAttribute, key); | |
257 } | |
258 | |
259 void archiveObject (string runtimeType, string type, string key, size_t id) | |
260 { | |
261 lastElement = lastElement.element(Tags.objectTag) | |
262 .attribute(Attributes.runtimeTypeAttribute, toDataType(name)) | |
263 .attribute(Attributes.typeAttribute, toDataType(type)) | |
264 .attribute(Attributes.keyAttribute, toDataType(key)) | |
265 .attribute(Attributes.idAttribute, toDataType(id)); | |
266 } | |
267 | |
268 void archivePointer (string key, size_t id) | |
269 { | |
270 lastElement = lastElement.element(Tags.pointerTag) | |
271 .attribute(Attributes.keyAttribute, toDataType(key)) | |
272 .attribute(Attributes.idAttribute, toDataType(id)); | |
273 } | |
274 | |
275 void archiveReference (size_t key, size_t id) | |
276 { | |
277 lastElement.element(Tags.referenceTag, toDataType(id)) | |
278 .attribute(Attributes.keyAttribute, toDataType(key)); | |
279 } | |
280 | |
281 /*void archiveSlice (Array array, Array slice) | |
282 { | |
283 sliceNode.parent.element(Tags.sliceTag, arrayNode.id) | |
284 .attribute(Attributes.keyAttribute, sliceNode.key) | |
285 .attribute(Attributes.offsetAttribute, toDataType((slice.ptr - array.ptr) / slice.elementSize)) | |
286 .attribute(Attributes.lengthAttribute, toDataType(slice.length)); | |
287 }*/ | |
288 | |
289 void archiveStruct (string type, size_t key, size_t id) | |
290 { | |
291 lastElement = lastElement.element(Tags.structTag) | |
292 .attribute(Attributes.typeAttribute, toDataType(type)) | |
293 .attribute(Attributes.keyAttribute, key); | |
294 } | |
295 | |
296 void archiveTypedef (string type, size_t key, size_t id) | |
297 { | |
298 lastElement = lastElement.element(Tags.typedefTag) | |
299 .attribute(Attributes.typeAttribute, toDataType(type)); | |
300 .attribute(Attributes.key, toDataType(key)); | |
301 } | |
302 | |
303 void archive (string value, string key, size_t id) | |
304 { | |
305 archiveString(value, key, id); | |
306 } | |
307 | |
308 void archive (wstring value, string key, size_t id) | |
309 { | |
310 archiveString(value, key, id); | |
311 } | |
312 | |
313 void archive (dstring value, string key, size_t id) | |
314 { | |
315 archiveString(value, key, id); | |
316 } | |
317 | |
318 private void archiveString (T) (T value, string key, size_t id) | |
319 { | |
320 alias BaseTypeOfArray!(T) ArrayBaseType; | |
321 auto array = Array(value.ptr, value.length, ArrayBaseType.sizeof); | |
322 | |
323 internalArchiveArray(ArrayBaseType.stringof, array, key, id, Tags.stringTag, toDataType(value)); | |
324 } | |
325 | |
326 void archive (bool value, string key, size_t id) | |
327 { | |
328 archivePrimitive (value, key); | |
329 } | |
330 | |
331 void archive (byte value, string key, size_t id) | |
332 { | |
333 archivePrimitive (value, key); | |
334 } | |
335 | |
336 void archive (cdouble value, string key, size_t id) | |
337 { | |
338 archivePrimitive (value, key); | |
339 } | |
340 | |
341 /*void archive (cent value, string key, size_t id) | |
342 { | |
343 archivePrimitive (value, key); | |
344 }*/ | |
345 | |
346 void archive (cfloat value, string key, size_t id) | |
347 { | |
348 archivePrimitive (value, key); | |
349 } | |
350 | |
351 void archive (char value, string key, size_t id) | |
352 { | |
353 archivePrimitive (value, key); | |
354 } | |
355 | |
356 void archive (creal value, string key, size_t id) | |
357 { | |
358 archivePrimitive (value, key); | |
359 } | |
360 | |
361 void archive (dchar value, string key, size_t id) | |
362 { | |
363 archivePrimitive (value, key); | |
364 } | |
365 | |
366 void archive (double value, string key, size_t id) | |
367 { | |
368 archivePrimitive (value, key); | |
369 } | |
370 | |
371 void archive (float value, string key, size_t id) | |
372 { | |
373 archivePrimitive (value, key); | |
374 } | |
375 | |
376 void archive (idouble value, string key, size_t id) | |
377 { | |
378 archivePrimitive (value, key); | |
379 } | |
380 | |
381 void archive (ifloat value, string key, size_t id) | |
382 { | |
383 archivePrimitive (value, key); | |
384 } | |
385 | |
386 void archive (int value, string key, size_t id) | |
387 { | |
388 archivePrimitive (value, key); | |
389 } | |
390 | |
391 void archive (ireal value, string key, size_t id) | |
392 { | |
393 archivePrimitive (value, key); | |
394 } | |
395 | |
396 void archive (long value, string key, size_t id) | |
397 { | |
398 archivePrimitive (value, key); | |
399 } | |
400 | |
401 void archive (real value, string key, size_t id) | |
402 { | |
403 archivePrimitive (value, key); | |
404 } | |
405 | |
406 void archive (short value, string key, size_t id) | |
407 { | |
408 archivePrimitive (value, key); | |
409 } | |
410 | |
411 void archive (ubyte value, string key, size_t id) | |
412 { | |
413 archivePrimitive (value, key); | |
414 } | |
415 | |
416 /*void archive (ucent value, string key, size_t id) | |
417 { | |
418 archivePrimitive (value, key); | |
419 }*/ | |
420 | |
421 void archive (uint value, string key, size_t id) | |
422 { | |
423 archivePrimitive (value, key); | |
424 } | |
425 | |
426 void archive (ulong value, string key, size_t id) | |
427 { | |
428 archivePrimitive (value, key); | |
429 } | |
430 | |
431 void archive (ushort value, string key, size_t id) | |
432 { | |
433 archivePrimitive (value, key); | |
434 } | |
435 | |
436 void archive (wchar value, string key, size_t id) | |
437 { | |
438 archivePrimitive (value, key); | |
439 } | |
440 | |
441 private void archivePrimitive (T) (T value, string key) | |
442 { | |
443 lastElement.element(toDataType(T.stringof), toDataType(value)) | |
444 .attribute(Attributes.keyAttribute, toDataType(key)); | |
445 } | |
446 | |
447 private void addArchivedArray (doc.Node parent, doc.Node lastElement, size_t id, string key, size_t elementSize, ) | |
448 { | |
449 arraysToBeArchived[Array(value)] = ArrayNode(parent, lastElement, id, key); | |
813 } | 450 } |
814 } | 451 } |