summaryrefslogtreecommitdiff
path: root/internal/xmpmeta/xml/serializer_impl.h
blob: 78131c5924885215c8da00939a57398c2f9bab17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_  // NOLINT
#define DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_  // NOLINT

#include <libxml/tree.h>

#include <string>
#include <unordered_map>

#include "xmpmeta/xml/serializer.h"

namespace photos_editing_formats {
namespace xml {

// Writes properties, lists, and child nodes into an XML structure.
//
// Usage example:
//  std::unordered_map<string, xmlNsPtr> namespaces;
//  string device_name("Device");
//  string cameras_name("Cameras");
//  string camera_name("Camera");
//  string audio_name("Audio");
//  string image_name("Image");
//  PopulateNamespaces(&namespaces);
//  DoSerialization();
//
//  // Serialization example.
//  void DoSerialization() {
//    xmlNodePtr device_node = xmlNewNode(nullptr, device_name);
//    Serializer device_serializer(namespaces, device_node);
//
//    std::unique_ptr<Serializer> cameras_serializer =
//        serializer->CreateListSerializer(cameras_name);
//    for (XdmCamera *camera : camera_list_) {
//      std::unique_ptr<Serializer> camera_serializer =
//          cameras_serializer->CreateItemSerializer("Device", camera_name);
//      success &= camera->Serialize(camera_serializer.get());
//
//      // Serialize Audio.
//      std::unique_ptr<Serializer> audio_serializer =
//          camera_serializer->CreateSerializer("Camera", audio_name);
//      audio_serializer->WriteProperty(camera_name, "Data", audio_data);
//      audio_serializer->WriteProperty(camera_name, "Mime", "audio/mp4");
//
//      // Serialize Image.
//      std::unique_ptr<Serializer> image_serializer =
//          camera_serializer->CreateSerializer("Camera", image_name);
//      image_serializer->WriteProperty(image_name, "Data", image_data);
//      image_serializer->WriteProperty(image_name, "Mime", "image/jpeg");
//
//      // Serialize ImagingModel.
//      std::unique_ptr<Serializer> imaging_model_serializer =
//          camera_serializer->CreateSerializer("Camera", "ImagingModel");
//      std::unique_ptr<Serializer> equirect_model_serializer =
//          imaging_model_serializer->CreateSerializer("Camera",
//                                                     "EquirectModel");
//      // Serializer equirect model fields here.
//    }
//  }
//
// Resulting XML structure:
// /*
//  * <Device>
//  *   <Device:Cameras>
//  *     <rdf:Seq>
//  *       <rdf:li>
//  *         <Device:Camera>
//  *             <Camera:Audio Audio:Mime="audio/mp4" Audio:Data="DataValue"/>
//  *             <Camera:Image Image:Mime="image/jpeg" Image:Data="DataValue"/>
//  *             <Camera:ImagingModel>
//  *               <Camera:EquirectModel ...properties/>
//  *             </Camera:ImagingModel>
//  *         </Device:Camera>
//  *       </rdf:li>
//  *     </rdf:Seq>
//  *   </Device:Cameras>
//  * </Device>
//  */
//
// // Namespace population example.
// void PopulateNamespaces(std::unordered_map<string, xmlNsPtr>* namespaces) {
//   xmlNsPtr device_ns =
//       xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/device")
//                ToXmlChar(device_name.data()));
//   xmlNsPtr camera_ns =
//       xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/camera")
//                ToXmlChar(camera_name.data()));
//   xmlNsPtr audio_ns =
//       xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/audio")
//                ToXmlChar(audio_name.data()));
//   xmlNsPtr image_ns =
//       xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/image")
//                ToXmlChar(image_name.data()));
//   namespaces->insert(device_name, device_ns);
//   namespaces->insert(camera_name, camera_ns);
//   namespaces->insert(audio_name, audio_ns);
//   namespaces->insert(image_name, image_ns);
// }

class SerializerImpl : public Serializer {
 public:
  // Constructor.
  // The prefix map is required if one of the CreateSerializer methods will be
  // called on this object. In particular, the RDF namespace must be present in
  // the prefix map if CreateItemSerializer or CreateListSerializer will be
  // called.
  // The namespaces map serves to keep XML namespace creation out of this
  // Serializer, to simplify memory management issues. Note that the libxml
  // xmlDocPtr will own all namespace and node pointers.
  // The namespaces parameter is a map of node names to full namespaces.
  // This contains all the namespaces (nodes and properties) that will be used
  // in serialization.
  // The node parameter is the caller node. This will be the node in which
  // serialization takes place in WriteProperties.
  SerializerImpl(const std::unordered_map<string, xmlNsPtr>& namespaces,
                 xmlNodePtr node);

  // Returns a new Serializer for an object that is part of an rdf:Seq list
  // of objects.
  // The parent serializer must be created with CreateListSerializer.
  std::unique_ptr<Serializer> CreateItemSerializer(
      const string& prefix, const string& item_name) const override;

  // Returns a new Serializer for a list of objects that correspond to an
  // rdf:Seq XML node, where each object is to be serialized as a child node of
  // every rdf:li node in the list.
  // The serializer is created on an rdf:Seq node, which is the child of a
  // newly created XML node with the name list_name.
  std::unique_ptr<Serializer> CreateListSerializer(
      const string& prefix, const string& list_name) const override;

  // Creates a serializer from the current serializer.
  // @param node_name The name of the caller node. This will be the parent of
  // any new nodes or properties set by this serializer.
  std::unique_ptr<Serializer> CreateSerializer(
      const string& node_ns_name, const string& node_name) const override;

  // Writes the property into the current node, prefixed with prefix if it
  // has a corresponding namespace href in namespaces_, fails otherwise.
  // Returns true if serialization is successful.
  // If prefix is empty, the property will not be set on an XML namespace.
  // name must not be empty.
  // value may be empty.
  bool WriteBoolProperty(const string& prefix, const string& name,
                         bool value) const override;
  bool WriteProperty(const string& prefix, const string& name,
                     const string& value) const override;

  // Writes the collection of numbers into a child rdf:Seq node.
  bool WriteIntArray(const string& prefix, const string& array_name,
                     const std::vector<int>& values) const override;
  bool WriteDoubleArray(const string& prefix, const string& array_name,
                        const std::vector<double>& values) const override;

  // Class-specific methods.
  // Constructs a serializer object and writes the xmlNsPtr objects in
  // namespaces_ to node_.
  static std::unique_ptr<SerializerImpl> FromDataAndSerializeNamespaces(
      const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node);

  // Disallow copying.
  SerializerImpl(const SerializerImpl&) = delete;
  void operator=(const SerializerImpl&) = delete;

 private:
  // Writes the xmlNsPtr objects in namespaces_ to node_.
  // Modifies namespaces_ by setting each xmlNsPtr's next pointer to the
  // subsequent entry in the collection.
  bool SerializeNamespaces();

  xmlNodePtr node_;
  std::unordered_map<string, xmlNsPtr> namespaces_;
};

}  // namespace xml
}  // namespace photos_editing_formats

#endif // DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_  // NOLINT