| |
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| |
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
| |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
5 |
| |
6 #ifndef mozilla_dom_DOMString_h |
| |
7 #define mozilla_dom_DOMString_h |
| |
8 |
| |
9 #include "nsStringGlue.h" |
| |
10 #include "nsStringBuffer.h" |
| |
11 #include "mozilla/Assertions.h" |
| |
12 #include "mozilla/Attributes.h" |
| |
13 #include "mozilla/Maybe.h" |
| |
14 #include "nsDOMString.h" |
| |
15 #include "nsIAtom.h" |
| |
16 |
| |
17 namespace mozilla { |
| |
18 namespace dom { |
| |
19 |
| |
20 /** |
| |
21 * A class for representing string return values. This can be either passed to |
| |
22 * callees that have an nsString or nsAString out param or passed to a callee |
| |
23 * that actually knows about this class and can work with it. Such a callee may |
| |
24 * call SetStringBuffer or SetOwnedString or SetOwnedAtom on this object, but |
| |
25 * only if it plans to keep holding a strong ref to the internal stringbuffer! |
| |
26 * |
| |
27 * The proper way to store a value in this class is to either to do nothing |
| |
28 * (which leaves this as an empty string), to call SetStringBuffer with a |
| |
29 * non-null stringbuffer, to call SetOwnedString, to call SetOwnedAtom, to call |
| |
30 * SetNull(), or to call AsAString() and set the value in the resulting |
| |
31 * nsString. These options are mutually exclusive! Don't do more than one of |
| |
32 * them. |
| |
33 * |
| |
34 * The proper way to extract a value is to check IsNull(). If not null, then |
| |
35 * check HasStringBuffer(). If that's true, check for a zero length, and if the |
| |
36 * length is nonzero call StringBuffer(). If the length is zero this is the |
| |
37 * empty string. If HasStringBuffer() returns false, call AsAString() and get |
| |
38 * the value from that. |
| |
39 */ |
| |
40 class MOZ_STACK_CLASS DOMString { |
| |
41 public: |
| |
42 DOMString() |
| |
43 : mStringBuffer(nullptr) |
| |
44 , mLength(0) |
| |
45 , mIsNull(false) |
| |
46 {} |
| |
47 ~DOMString() |
| |
48 { |
| |
49 MOZ_ASSERT(mString.empty() || !mStringBuffer, |
| |
50 "Shouldn't have both present!"); |
| |
51 } |
| |
52 |
| |
53 operator nsString&() |
| |
54 { |
| |
55 return AsAString(); |
| |
56 } |
| |
57 |
| |
58 nsString& AsAString() |
| |
59 { |
| |
60 MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?"); |
| |
61 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
| |
62 if (mString.empty()) { |
| |
63 mString.construct(); |
| |
64 } |
| |
65 return mString.ref(); |
| |
66 } |
| |
67 |
| |
68 bool HasStringBuffer() const |
| |
69 { |
| |
70 MOZ_ASSERT(mString.empty() || !mStringBuffer, |
| |
71 "Shouldn't have both present!"); |
| |
72 MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first"); |
| |
73 return mString.empty(); |
| |
74 } |
| |
75 |
| |
76 // Get the stringbuffer. This can only be called if HasStringBuffer() |
| |
77 // returned true and StringBufferLength() is nonzero. If that's true, it will |
| |
78 // never return null. |
| |
79 nsStringBuffer* StringBuffer() const |
| |
80 { |
| |
81 MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first"); |
| |
82 MOZ_ASSERT(HasStringBuffer(), |
| |
83 "Don't ask for the stringbuffer if we don't have it"); |
| |
84 MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?"); |
| |
85 MOZ_ASSERT(mStringBuffer, |
| |
86 "If our length is nonzero, we better have a stringbuffer."); |
| |
87 return mStringBuffer; |
| |
88 } |
| |
89 |
| |
90 // Get the length of the stringbuffer. Can only be called if |
| |
91 // HasStringBuffer(). |
| |
92 uint32_t StringBufferLength() const |
| |
93 { |
| |
94 MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer"); |
| |
95 return mLength; |
| |
96 } |
| |
97 |
| |
98 void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength) |
| |
99 { |
| |
100 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
| |
101 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
| |
102 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
| |
103 MOZ_ASSERT(aStringBuffer, "Why are we getting null?"); |
| |
104 mStringBuffer = aStringBuffer; |
| |
105 mLength = aLength; |
| |
106 } |
| |
107 |
| |
108 void SetOwnedString(const nsAString& aString) |
| |
109 { |
| |
110 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
| |
111 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
| |
112 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
| |
113 nsStringBuffer* buf = nsStringBuffer::FromString(aString); |
| |
114 if (buf) { |
| |
115 SetStringBuffer(buf, aString.Length()); |
| |
116 } else if (aString.IsVoid()) { |
| |
117 SetNull(); |
| |
118 } else if (!aString.IsEmpty()) { |
| |
119 AsAString() = aString; |
| |
120 } |
| |
121 } |
| |
122 |
| |
123 enum NullHandling |
| |
124 { |
| |
125 eTreatNullAsNull, |
| |
126 eTreatNullAsEmpty, |
| |
127 eNullNotExpected |
| |
128 }; |
| |
129 |
| |
130 void SetOwnedAtom(nsIAtom* aAtom, NullHandling aNullHandling) |
| |
131 { |
| |
132 MOZ_ASSERT(mString.empty(), "We already have a string?"); |
| |
133 MOZ_ASSERT(!mIsNull, "We're already set as null"); |
| |
134 MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?"); |
| |
135 MOZ_ASSERT(aAtom || aNullHandling != eNullNotExpected); |
| |
136 if (aNullHandling == eNullNotExpected || aAtom) { |
| |
137 SetStringBuffer(aAtom->GetStringBuffer(), aAtom->GetLength()); |
| |
138 } else if (aNullHandling == eTreatNullAsNull) { |
| |
139 SetNull(); |
| |
140 } |
| |
141 } |
| |
142 |
| |
143 void SetNull() |
| |
144 { |
| |
145 MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null"); |
| |
146 MOZ_ASSERT(mString.empty(), "Should have no string if null"); |
| |
147 mIsNull = true; |
| |
148 } |
| |
149 |
| |
150 bool IsNull() const |
| |
151 { |
| |
152 MOZ_ASSERT(!mStringBuffer || mString.empty(), |
| |
153 "How could we have a stringbuffer and a nonempty string?"); |
| |
154 return mIsNull || (!mString.empty() && mString.ref().IsVoid()); |
| |
155 } |
| |
156 |
| |
157 void ToString(nsAString& aString) |
| |
158 { |
| |
159 if (IsNull()) { |
| |
160 SetDOMStringToNull(aString); |
| |
161 } else if (HasStringBuffer()) { |
| |
162 if (StringBufferLength() == 0) { |
| |
163 aString.Truncate(); |
| |
164 } else { |
| |
165 StringBuffer()->ToString(StringBufferLength(), aString); |
| |
166 } |
| |
167 } else { |
| |
168 aString = AsAString(); |
| |
169 } |
| |
170 } |
| |
171 |
| |
172 private: |
| |
173 // We need to be able to act like a string as needed |
| |
174 Maybe<nsAutoString> mString; |
| |
175 |
| |
176 // For callees that know we exist, we can be a stringbuffer/length/null-flag |
| |
177 // triple. |
| |
178 nsStringBuffer* mStringBuffer; |
| |
179 uint32_t mLength; |
| |
180 bool mIsNull; |
| |
181 }; |
| |
182 |
| |
183 } // namespace dom |
| |
184 } // namespace mozilla |
| |
185 |
| |
186 #endif // mozilla_dom_DOMString_h |