summaryrefslogtreecommitdiff
path: root/dom/base/nsXMLContentSerializer.h
blob: b48f9411d5c561fe9e7def9364ca8425c2879184 (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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * nsIContentSerializer implementation that can be used with an
 * nsIDocumentEncoder to convert an XML DOM to an XML string that
 * could be parsed into more or less the original DOM.
 */

#ifndef nsXMLContentSerializer_h__
#define nsXMLContentSerializer_h__

#include "mozilla/Attributes.h"
#include "nsIContentSerializer.h"
#include "nsISupportsUtils.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsString.h"

#define kIndentStr NS_LITERAL_STRING("  ")
#define kEndTag NS_LITERAL_STRING("</")

class nsIAtom;
class nsINode;

class nsXMLContentSerializer : public nsIContentSerializer {
 public:
  nsXMLContentSerializer();

  NS_DECL_ISUPPORTS

  NS_IMETHOD Init(uint32_t flags, uint32_t aWrapColumn,
                  const char* aCharSet, bool aIsCopying,
                  bool aRewriteEncodingDeclaration) override;

  NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
                        int32_t aEndOffset, nsAString& aStr) override;

  NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
                                int32_t aStartOffset, int32_t aEndOffset,
                                nsAString& aStr) override;

  NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
                                         int32_t aStartOffset,
                                         int32_t aEndOffset,
                                         nsAString& aStr) override;

  NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset,
                           int32_t aEndOffset, nsAString& aStr) override;
  
  NS_IMETHOD AppendDoctype(nsIContent *aDoctype,
                           nsAString& aStr) override;

  NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
                                mozilla::dom::Element* aOriginalElement,
                                nsAString& aStr) override;

  NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
                              mozilla::dom::Element* aOriginalElement,
                              nsAString& aStr) override;

  NS_IMETHOD Flush(nsAString& aStr) override { return NS_OK; }

  NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
                                 nsAString& aStr) override;

 protected:
  virtual ~nsXMLContentSerializer();

  /**
   * Appends a char16_t character and increments the column position
   */
  MOZ_MUST_USE
  bool AppendToString(const char16_t aChar,
                      nsAString& aOutputStr);

  /**
   * Appends a nsAString string and increments the column position
   */
  MOZ_MUST_USE
  bool AppendToString(const nsAString& aStr,
                      nsAString& aOutputStr);

  /**
   * Appends a string by replacing all line-endings
   * by mLineBreak, except in the case of raw output.
   * It increments the column position.
   */
  MOZ_MUST_USE
  bool AppendToStringConvertLF(const nsAString& aStr,
                               nsAString& aOutputStr);

  /**
   * Appends a string by wrapping it when necessary.
   * It updates the column position.
   */
  MOZ_MUST_USE
  bool AppendToStringWrapped(const nsASingleFragmentString& aStr,
                             nsAString& aOutputStr);

  /**
   * Appends a string by formating and wrapping it when necessary
   * It updates the column position.
   */
  MOZ_MUST_USE
  bool AppendToStringFormatedWrapped(const nsASingleFragmentString& aStr,
                                     nsAString& aOutputStr);

  // used by AppendToStringWrapped
  MOZ_MUST_USE
  bool AppendWrapped_WhitespaceSequence(
          nsASingleFragmentString::const_char_iterator &aPos,
          const nsASingleFragmentString::const_char_iterator aEnd,
          const nsASingleFragmentString::const_char_iterator aSequenceStart,
          nsAString &aOutputStr);

  // used by AppendToStringFormatedWrapped
  MOZ_MUST_USE
  bool AppendFormatedWrapped_WhitespaceSequence(
          nsASingleFragmentString::const_char_iterator &aPos,
          const nsASingleFragmentString::const_char_iterator aEnd,
          const nsASingleFragmentString::const_char_iterator aSequenceStart,
          bool &aMayIgnoreStartOfLineWhitespaceSequence,
          nsAString &aOutputStr);

  // used by AppendToStringWrapped and AppendToStringFormatedWrapped
  MOZ_MUST_USE
  bool AppendWrapped_NonWhitespaceSequence(
          nsASingleFragmentString::const_char_iterator &aPos,
          const nsASingleFragmentString::const_char_iterator aEnd,
          const nsASingleFragmentString::const_char_iterator aSequenceStart,
          bool &aMayIgnoreStartOfLineWhitespaceSequence,
          bool &aSequenceStartAfterAWhiteSpace,
          nsAString &aOutputStr);

  /**
   * add mLineBreak to the string
   * It updates the column position and other flags.
   */
  MOZ_MUST_USE
  bool AppendNewLineToString(nsAString& aOutputStr);


  /**
   * Appends a string by translating entities
   * It doesn't increment the column position
   */
  MOZ_MUST_USE
  virtual bool AppendAndTranslateEntities(const nsAString& aStr,
                                          nsAString& aOutputStr);

  /**
   * retrieve the text content of the node and append it to the given string
   * It doesn't increment the column position
   */
  nsresult AppendTextData(nsIContent* aNode,
                          int32_t aStartOffset,
                          int32_t aEndOffset,
                          nsAString& aStr,
                          bool aTranslateEntities);

  virtual nsresult PushNameSpaceDecl(const nsAString& aPrefix,
                                     const nsAString& aURI,
                                     nsIContent* aOwner);
  void PopNameSpaceDeclsFor(nsIContent* aOwner);

  /**
   * The problem that ConfirmPrefix fixes is that anyone can insert nodes
   * through the DOM that have a namespace URI and a random or empty or
   * previously existing prefix that's totally unrelated to the prefixes
   * declared at that point through xmlns attributes.  So what ConfirmPrefix
   * does is ensure that we can map aPrefix to the namespace URI aURI (for
   * example, that the prefix is not already mapped to some other namespace).
   * aPrefix will be adjusted, if necessary, so the value of the prefix
   * _after_ this call is what should be serialized.
   * @param aPrefix the prefix that may need adjusting
   * @param aURI the namespace URI we want aPrefix to point to
   * @param aElement the element we're working with (needed for proper default
   *                 namespace handling)
   * @param aIsAttribute true if we're confirming a prefix for an attribute.
   * @return true if we need to push the (prefix, uri) pair on the namespace
   *                 stack (note that this can happen even if the prefix is
   *                 empty).
   */
  bool ConfirmPrefix(nsAString& aPrefix,
                       const nsAString& aURI,
                       nsIContent* aElement,
                       bool aIsAttribute);
  /**
   * GenerateNewPrefix generates a new prefix and writes it to aPrefix
   */
  void GenerateNewPrefix(nsAString& aPrefix);

  uint32_t ScanNamespaceDeclarations(nsIContent* aContent,
                                     nsIContent *aOriginalElement,
                                     const nsAString& aTagNamespaceURI);

  MOZ_MUST_USE
  virtual bool SerializeAttributes(nsIContent* aContent,
                                   nsIContent *aOriginalElement,
                                   nsAString& aTagPrefix,
                                   const nsAString& aTagNamespaceURI,
                                   nsIAtom* aTagName,
                                   nsAString& aStr,
                                   uint32_t aSkipAttr,
                                   bool aAddNSAttr);

  MOZ_MUST_USE
  bool SerializeAttr(const nsAString& aPrefix,
                     const nsAString& aName,
                     const nsAString& aValue,
                     nsAString& aStr,
                     bool aDoEscapeEntities);

  bool IsJavaScript(nsIContent * aContent,
                      nsIAtom* aAttrNameAtom,
                      int32_t aAttrNamespaceID,
                      const nsAString& aValueString);

  /**
   * This method can be redefined to check if the element can be serialized.
   * It is called when the serialization of the start tag is asked 
   * (AppendElementStart)
   * In this method you can also force the formating
   * by setting aForceFormat to true.
   * @return boolean  true if the element can be output
   */
  virtual bool CheckElementStart(nsIContent * aContent,
                                   bool & aForceFormat,
                                   nsAString& aStr,
                                   nsresult& aResult);

  /**
   * This method is responsible for appending the '>' at the end of the start
   * tag, possibly preceded by '/' and maybe a ' ' before that too.
   *
   * aElement and aOriginalElement are the same as the corresponding arguments
   * to AppendElementStart.
   */
  MOZ_MUST_USE
  bool AppendEndOfElementStart(mozilla::dom::Element* aEleemnt,
                               mozilla::dom::Element* aOriginalElement,
                               nsAString& aStr);

  /**
   * This method can be redefine to serialize additional things just after
   * after the serialization ot the start tag.
   * (called at the end of AppendElementStart)
   */
  MOZ_MUST_USE
  virtual bool AfterElementStart(nsIContent* aContent,
                                 nsIContent* aOriginalElement,
                                 nsAString& aStr) { return true; };

  /**
   * This method can be redefined to check if the element can be serialized.
   * It is called when the serialization of the end tag is asked 
   * (AppendElementEnd)
   * In this method you can also force the formating
   * by setting aForceFormat to true.
   * @return boolean  true if the element can be output
   */
  virtual bool CheckElementEnd(mozilla::dom::Element* aElement,
                               mozilla::dom::Element* aOriginalElement,
                               bool& aForceFormat,
                               nsAString& aStr);

  /**
   * This method can be redefine to serialize additional things just after
   * after the serialization ot the end tag.
   * (called at the end of AppendElementStart)
   */
  virtual void AfterElementEnd(nsIContent * aContent,
                               nsAString& aStr) { };

  /**
   * Returns true if a line break should be inserted before an element open tag
   */
  virtual bool LineBreakBeforeOpen(int32_t aNamespaceID, nsIAtom* aName);

  /**
   * Returns true if a line break should be inserted after an element open tag
   */
  virtual bool LineBreakAfterOpen(int32_t aNamespaceID, nsIAtom* aName);

  /**
   * Returns true if a line break should be inserted after an element close tag
   */
  virtual bool LineBreakBeforeClose(int32_t aNamespaceID, nsIAtom* aName);

  /**
   * Returns true if a line break should be inserted after an element close tag
   */
  virtual bool LineBreakAfterClose(int32_t aNamespaceID, nsIAtom* aName);

  /**
   * add intendation. Call only in the case of formating and if the current
   * position is at 0. It updates the column position.
   */
  MOZ_MUST_USE
  bool AppendIndentation(nsAString& aStr);

  MOZ_MUST_USE
  bool IncrIndentation(nsIAtom* aName);
  void DecrIndentation(nsIAtom* aName);

  // Functions to check for newlines that needs to be added between nodes in
  // the root of a document. See mAddNewlineForRootNode
  MOZ_MUST_USE
  bool MaybeAddNewlineForRootNode(nsAString& aStr);
  void MaybeFlagNewlineForRootNode(nsINode* aNode);

  // Functions to check if we enter in or leave from a preformated content
  virtual void MaybeEnterInPreContent(nsIContent* aNode);
  virtual void MaybeLeaveFromPreContent(nsIContent* aNode);

  bool ShouldMaintainPreLevel() const;
  int32_t PreLevel() const {
    MOZ_ASSERT(ShouldMaintainPreLevel());
    return mPreLevel;
  }
  int32_t& PreLevel() {
    MOZ_ASSERT(ShouldMaintainPreLevel());
    return mPreLevel;
  }

  int32_t mPrefixIndex;

  struct NameSpaceDecl {
    nsString mPrefix;
    nsString mURI;
    nsIContent* mOwner;
  };

  nsTArray<NameSpaceDecl> mNameSpaceStack;

  // nsIDocumentEncoder flags
  MOZ_INIT_OUTSIDE_CTOR uint32_t  mFlags;

  // characters to use for line break
  nsString  mLineBreak;

  // The charset that was passed to Init()
  nsCString mCharset;
  
  // current column position on the current line
  uint32_t   mColPos;

  // true = pretty formating should be done (OutputFormated flag)
  MOZ_INIT_OUTSIDE_CTOR bool mDoFormat;

  // true = no formatting,(OutputRaw flag)
  // no newline convertion and no rewrap long lines even if OutputWrap is set.
  MOZ_INIT_OUTSIDE_CTOR bool mDoRaw;

  // true = wrapping should be done (OutputWrap flag)
  MOZ_INIT_OUTSIDE_CTOR bool mDoWrap;

  // true = we can break lines (OutputDisallowLineBreaking flag)
  MOZ_INIT_OUTSIDE_CTOR bool mAllowLineBreaking;

  // number of maximum column in a line, in the wrap mode
  MOZ_INIT_OUTSIDE_CTOR uint32_t   mMaxColumn;

  // current indent value
  nsString   mIndent;

  // this is the indentation level after the indentation reached
  // the maximum length of indentation
  int32_t    mIndentOverflow;

  // says if the indentation has been already added on the current line
  bool mIsIndentationAddedOnCurrentLine;

  // the string which is currently added is in an attribute
  bool mInAttribute;

  // true = a newline character should be added. It's only
  // useful when serializing root nodes. see MaybeAddNewlineForRootNode and
  // MaybeFlagNewlineForRootNode
  bool mAddNewlineForRootNode;

  // Indicates that a space will be added if and only if content is
  // continued on the same line while serializing source.  Otherwise,
  // the newline character acts as the whitespace and no space is needed.
  // used when mDoFormat = true
  bool          mAddSpace;

  // says that if the next string to add contains a newline character at the
  // begining, then this newline character should be ignored, because a
  // such character has already been added into the output string
  bool          mMayIgnoreLineBreakSequence;

  bool          mBodyOnly;
  int32_t       mInBody;

private:
  // number of nested elements which have preformated content
  MOZ_INIT_OUTSIDE_CTOR int32_t mPreLevel;
};

nsresult
NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);

#endif