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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
|
---
title: Strings
slug: Mozilla/Tech/XPCOM/Guide/Internal_strings
tags:
- XPCOM
- 所有分类
translation_of: Mozilla/Tech/XPCOM/Guide/Internal_strings
---
<p> </p>
<h2 id="Preface" name="Preface">Preface</h2>
<div>
<p>by Alec Flett<br>
Thanks to David Baron for <a class="external" href="http://dbaron.org/mozilla/coding-practices">actual docs</a>,<br>
Peter Annema for lots of direction,<br>
Myk Melez for some more docs, and<br>
David Bradley for a diagram<br>
Revised by Darin Fisher for Mozilla 1.7<br>
Revised by Jungshik Shin to clarify character encoding issues</p>
</div>
<p>This guide will attempt to document the plethora of string classes, and hopefully provide an answer to the age old question, "what string class should I use here?"</p>
<div style="border: solid thin steelblue; padding: 0.5em;">
<p>If you are a Mozilla embedder or if you are writing an XPCOM component that will be distributed separately from the Mozilla code base, then this string guide is most likely not for you! Provided you are developing against Mozilla 1.7 or later, you should instead be using the new minimal <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/glue/nsStringAPI.h" rel="custom">Mozilla string API</a> and in particular the <a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/string/public/nsEmbedString.h" rel="custom">nsEmbedString</a> class.</p>
</div>
<p>In a hurry? Go check out the <a href="cn/XPCOM/String_Quick_Reference">String Quick-Reference</a> (<a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">). </a></p>
<h2 id="Introduction" name="Introduction"><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Introduction </a></h2>
<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">The string classes are a library of C++ classes which are used to manage buffers of unicode and single-byte character strings. They reside in the mozilla codebase in the <code></code></a><code><a href="https://dxr.mozilla.org/mozilla-central/source/xpcom/string" rel="custom">xpcom/string</a></code> directory. </p>
<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Abstract (interface) classes begin with "nsA" and concrete classes simply begin with "ns". Classes with a "<code>CString</code>" in the name store 8-bit bytes (<code>char</code>'s) which may refer to single byte ASCII strings, or multibyte Unicode strings encoded in UTF-8 or a (multibyte or single byte) legacy character encoding (e.g. ISO-8859-1, Shift_JIS, GB2312, KOI8-R). All other classes simply have "<code>String</code>" in their name and refer to 16-bit strings made up of <code>PRUnichar</code>'s, For example: <code>nsAString</code> is an abstract class for storing Unicode characters in UTF-16 encoding, and <code>nsDependentCString</code> is a concrete class which stores a 8-bit string. Every 16-bit string class has an equivalent 8-bit string class. For example: <code>nsCString</code> is the 8-bit string class which corresponds to <code>nsString</code>. </a></p>
<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">8-bit and 16-bit string classes have completely separate base classes, but share the same APIs. As a result, you cannot assign a 8-bit string to a 16-bit string without some kind of conversion helper class or routine. For the purpose of this document, we will refer to the 16-bit string classes in class documentation. It is safe to assume that every 16-bit class has an equivalent 8-bit class. </a></p>
<h2 id="String_Guidelines" name="String_Guidelines"><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">String Guidelines </a></h2>
<p><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Follow these simple rules in your code to keep your fellow developers, reviewers, and users happy. </a></p>
<ul>
<li><a class="external" href="http://www.mozilla.org/projects/xpcom/string-quickref.html">Avoid </a><code><a href="#Unicode_Conversion_ns.2ACString_vs._ns.2AString">*WithConversion</a></code> functions at all costs: <code>AssignWithConversion</code>, <code>AppendWithConversion</code>, <code>EqualsWithConversion</code>, etc</li>
<li>Use the most abstract string class that you can. Usually this is:
<ul>
<li><code><a href="#The_Abstract_Classes">nsAString</a></code> for function parameters</li>
<li><code><a href="#The_Concrete_Classes_-_which_classes_to_use_when">nsString</a></code> for member variables</li>
<li><a href="#The_Concrete_Classes_-_which_classes_to_use_when"><code>nsAutoString</code> or <code>nsXPIDLString</code></a> for local (stack-based) variables</li>
</ul>
</li>
<li>Use <a href="#Literal_Strings"><code>NS_LITERAL_[C]STRING</code> / <code>NS_NAMED_LITERAL_[C]STRING</code></a> to represent literal strings (i.e. "foo") as nsAString-compatible objects.</li>
<li>Use <a href="#String_Concatenation">string concatenation</a> (i.e. the "+" operator) when combining strings.</li>
<li>Use <code><a href="#Raw_Character_Pointers">nsDependentString</a></code> when you have a raw character pointer that you need to convert to an nsAString-compatible string.</li>
<li>Use <code><a href="#Substrings_.28string_fragments.29">Substring()</a></code> to extract fragments of existing strings.</li>
<li>Use <a href="#Iterators">iterators</a> to parse and extract string fragments.</li>
</ul>
<h2 id="The_Abstract_Classes" name="The_Abstract_Classes">The Abstract Classes</h2>
<p>Every string class derives from <code>nsAString</code> (or <code>nsACString</code>). This class provides the fundamental interface for access and manipulation of strings. While concrete classes derive from <code>nsAString</code>, <code>nsAString</code> itself cannot be instantiated.</p>
<p>This is very similar to the idea of an "interface" that mozilla uses to describe abstract object descriptions in the rest of the codebase. In the case of interfaces, class names begin with "nsI" where "I" refers to "Interface". In the case of strings, abstract classes begin with "nsA" and the "A" means "Abstract".</p>
<p>There are a number of abstract classes which derive from <code>nsAString</code>. These abstract subclasses also cannot be instantiated, but they describe a string in slightly more detail than <code>nsAString</code>. They guarantee that the underlying implementation behind the abstract class provides specific capabilities above and beyond <code>nsAString</code>.</p>
<p>The list below describes the main base classes. Once you are familiar with them, see the appendix describing What Class to Use When.</p>
<ul>
<li><b><code>nsAString</code></b>: the abstract base class for all strings. It provides an API for assignment, individual character access, basic manipulation of characters in the string, and string comparison. This class corresponds to the XPIDL <code>AString</code> parameter type.</li>
<li><b><code>nsSubstring</code></b>: the common base class for all of the string classes. Provides optimized access to data within the string. A <code>nsSubstring</code> is not necessarily null-terminated. (For backwards compatibility, <code>nsASingleFragmentString</code> is a typedef for this string class.)</li>
<li><b><code>nsString</code></b>: builds on <code>nsSubstring</code> by guaranteeing a null-terminated storage. This allows for a method (<code>.get()</code>) to access the underlying character buffer. (For backwards compatibility, <code>nsAFlatString</code> is a typedef for this string class.)</li>
</ul>
<p>The remainder of the string classes inherit from either <code>nsSubstring</code> or <code>nsString</code>. Thus, every string class is compatible with <code>nsAString</code>.</p>
<p>It's important to note that <code>nsSubstring</code> and <code>nsAString</code> both represent a contiguous array of characters that are not necessarily null-terminated. One might ask then ask why two different yet similar string classes need to exist. Well, <code>nsSubstring</code> exists primarily as an optimization since <code>nsAString</code> must retain binary compatibility with the frozen <code>nsAString</code> class that shipped with Mozilla 1.0. Up until the release of Mozilla 1.7, <code>nsAString</code> was capable of representing a string broken into multiple fragments. The cost associated with supporting multi-fragment strings was high and offered limited benefits. It was decided to eliminate support for multi-fragment strings in an effort to reduce the complexity of the string classes and improve performance. See <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=231995" title='FIXED: Exploring nsAString "defragmentation"'>bug 231995</a> for more details.</p>
<p>Though <code>nsSubstring</code> provides a more efficient interface to its underlying buffer than <code>nsAString</code>, <code>nsAString</code> is still the most commonly used class for parameter passing. This is because it is the string class corresponding to <code>AString</code> in XPIDL. Therefore, this string guide will continue to discuss the string classes with an emphasis on <code>nsAString</code>.</p>
<p>Since every string derives from <code>nsAString</code> (or <code>nsACString</code>), they all share a simple API. Common read-only methods:</p>
<ul>
<li><b><code>.Length()</code></b> - the number of code units (bytes for 8-bit string classes and PRUnichar's for 16-bit string classes) in the string.</li>
<li><b><code>.IsEmpty()</code></b> - the fastest way of determining if the string has any value. Use this instead of testing <code>string.Length</code> == 0</li>
<li><b><code>.Equals(string)</code></b> - TRUE if the given string has the same value as the current string.</li>
</ul>
<p>Common methods that modify the string:</p>
<ul>
<li><b><code>.Assign(string)</code></b> - Assigns a new value to the string.</li>
<li><b><code>.Append(string)</code></b> - Appends a value to the string.</li>
<li><b><code>.Insert(string, position)</code></b> - Inserts the given string before the code unit at position.</li>
<li><b><code>.Truncate(length)</code></b> - shortens the string to the given length.</li>
</ul>
<p>Complete documentation can be found in the <a href="#Appendix_B_-_nsAString_Reference">Appendix</a>.</p>
<h3 id="Read-only_strings" name="Read-only_strings">Read-only strings</h3>
<p>The <code>const</code> attribute on a string determines if the string is writable. If a string is defined as a <code>const nsAString</code> then the data in the string cannot be manipulated. If one tries to call a non-<code>const</code> method on a <code>const</code> string the compiler will flag this as an error at build time.</p>
<p>For example:</p>
<pre class="eval">void nsFoo::ReverseCharacters(nsAString& str) {
...
str.Assign(reversedStr); // modifies the string
}
</pre>
<p>This should not compile, because you're assigning to a <code>const</code> class:</p>
<pre class="eval">void nsFoo::ReverseCharacters(const nsAString& str) {
...
<b>str.Assign(reversedStr);</b>
}
</pre>
<h3 id="As_function_parameters" name="As_function_parameters">As function parameters</h3>
<p>It is recommended that you use the most abstract interface possible as a function parameter, instead of using concrete classes. The convention is to use C++ references (the '&' character) instead of pointers (the '*' character) when passing string references around. For example:</p>
<pre class="eval">// abstract reference
nsFoo::PrintString(<b>const nsAString&</b> str) {..}
// using a concrete class!
nsFoo::PrintString(<b>const nsString&</b> str) {..}
// using a pointer!
nsFoo::PrintString(<b>const nsAString*</b> str) {..}
</pre>
<p>The abstract classes are also sometimes used to store temporary references to objects. You can see both of these uses in <a href="#Common_Patterns">Common Patterns</a>, below.</p>
<p><b>NOTE:</b> While using abstract string classes increases the re-usability of your methods, it also incurs a codesize and performance penalty. Therefore, when writing methods that will only ever be used within the confines of your source file or module, it is better to use <b><code>const nsSubstring&</code></b> for input parameters and <b><code>nsString&</code></b> for output parameters. --Darin</p>
<h2 id="The_Concrete_Classes_-_which_classes_to_use_when" name="The_Concrete_Classes_-_which_classes_to_use_when">The Concrete Classes - which classes to use when</h2>
<p>The concrete classes are for use in code that actually needs to store string data. The most common uses of the concrete classes are as local variables, and members in classes or structs. Whereas the abstract classes differ in storage mechansim, for the most part the concrete classes differ in storage policy.</p>
<p>The following is a list of the most common concrete classes. Once you are familiar with them, see the appendix describing <a href="#Appendix_A_-_What_class_to_use_when">What Class to Use When.</a></p>
<ul>
<li><code><b>nsString / nsCString</b></code>- a null-terminated string whose buffer is allocated on the heap. Destroys its buffer when the string object goes away.</li>
<li><code><b>nsAutoString / nsCAutoString</b></code>- derived from <code>nsString</code>, a string which owns a 64 code unit buffer in the same storage space as the string itself. If a string less than 64 code units is assigned to an <code>nsAutoString</code>, then no extra storage will be allocated. For larger strings, a new buffer is allocated on the heap.</li>
<li><code><b>nsXPIDLString / nsXPIDLCString</b></code>- derived from <code>nsString</code>, this class supports the <code>getter_Copies()</code> operator which allows easy access to XPIDL <code>out wstring / string</code> parameters. This class also supports the notion of a null-valued buffer, whereas <code>nsString</code>'s buffer is never null.</li>
<li><code><b>nsDependentString</b></code>- derived from <code>nsString</code>, this string does
<i>
not</i>
own its buffer. It is useful for converting a raw string (<code>const PRUnichar*</code> or <code>const char*</code>) into a class of type <code>nsAString</code>.</li>
<li><code><b>nsPrintfCString</b></code>- derived from <code>nsCString</code>, this string behaves like an <code>nsCAutoString</code>. The constructor takes parameters which allows it to construct a 8-bit string from a <code>printf</code>-style format string and parameter list.</li>
<li><code><b>NS_LITERAL_STRING/NS_NAMED_LITERAL_STRING</b></code>- these convert a literal string (such as "abc") to a <code>nsString</code> or a subclass of <code>nsString</code>. On platforms supporting double-byte string literals (e.g., MSVC++ or GCC with the -fshort-wchar option), these are simply macros around the <code>nsDependentString</code> class. They are slightly faster than just wrapping them with an <code>nsDependentString</code> because they use the compiler to calculate their length, and they also hide the messy cross-platform details of non-byte literal strings.</li>
</ul>
<p>There are also a number of concrete classes that are created as a side-effect of helper routines, etc. You should avoid direct use of these classes. Let the string library create the class for you.</p>
<ul>
<li><code><b>nsSubstringTuple</b></code> - created via <a href="#String_Concatenation">string concatenation</a></li>
<li><code><b>nsDependentSubstring</b></code> - created through <a href="#Substrings_.28string_fragments.29">Substring</a></li>
<li><code><b>nsPromiseFlatString</b></code> - created through <code><b><a href="#Raw_Character_Pointers">PromiseFlatString()</a></b></code></li>
</ul>
<p>Of course, there are times when it is necessary to reference these string classes in your code, but as a general rule they should be avoided.</p>
<h2 id="Iterators" name="Iterators">Iterators</h2>
<p>Iterators are objects that retain a reference to a position in a string. In some ways they are like a number which refers to an index in an array, or a character-pointer that refers to a position in a character string. They also provide a syntactic means to distinguish between reading and writing to a string.</p>
<p>Iterators are most often used to extract substrings of a string. They provide the capability to modify the contents of a string, but often helper routines, or the string's own methods are quicker at complex string transformations.</p>
<p>Iterators are declared from the string class which they are iterating:</p>
<pre class="eval">nsAString::const_iterator start, end; // reading-only iterators for nsAString
nsString::iterator substr_start, substr_end; // writing iterators for nsString
</pre>
<p>Iterators are initialized with one of 4 methods on the string you wish to reference:</p>
<pre class="eval">// let's read from 'str'
str.BeginReading(start); // initialize 'start' to the beginning of 'str'
str.EndReading(end); // 'end' will be at the end of the string
// say we also want to write to 'url'
url.BeginWriting(substr_start);
url.EndWriting(substr_end);
</pre>
<p>You can access the code unit that an iterator points to with the dereference operator *.</p>
<pre class="eval">if (*start == '[')
printf("Starts with a bracket\n");
</pre>
<p>Note in the above examples, that '<code>end</code>' and '<code>substr_end</code>' will actually point to the code unit past the end of the string, so you should never dereference the direct result of <code>.EndReading()</code>.</p>
<p>You can test if two iterators point to the same position with == or !=. You can advance iterators with ++. Putting the ++ before your iterator is preferred, and will prevent creation of a temporary iterator.</p>
<pre class="eval">while (start != end) // iterate through the whole string
++start;
</pre>
<p>You can effectively write to a string with writing iterators (as opposed to const-iterators):</p>
<pre class="eval">// change all * to !
while (substr_start != substr_end) {
if (*substr_start == '*')
*substr_start = '!';
++substr_start;
}
</pre>
<p>With the patch for <a class="external" href="http://bugzilla.mozilla.org/show_bug.cgi?id=231995">bug 231995</a>, this loop is now as efficient as iterating with raw character pointers.</p>
<h2 id="Helper_Classes_and_Functions" name="Helper_Classes_and_Functions">Helper Classes and Functions</h2>
<h3 id="Searching_strings_-_looking_for_substrings.2C_characters.2C_etc." name="Searching_strings_-_looking_for_substrings.2C_characters.2C_etc.">Searching strings - looking for substrings, characters, etc.</h3>
<p><code>FindInReadable()</code> is the replacement for the old <code>string.Find(..)</code>. The syntax is:</p>
<pre class="eval">PRBool FindInReadable(const nsAString& pattern,
nsAString::const_iterator start, nsAString::const_iterator end,
nsStringComparator& aComparator = nsDefaultStringComparator());
</pre>
<p>To use this, <code>start</code> and <code>end</code> should point to the beginning and end of a string that you would like to search. If the search string is found, <code>start</code> and <code>end</code> will be adjusted to point to the beginning and end of the found pattern. The return value is PR_TRUE or PR_FALSE, indicating whether or not the string was found.</p>
<p>An example:</p>
<pre class="eval">const nsAString& str = GetSomeString();
nsAString::const_iterator start, end;
str.BeginReading(start);
str.EndReading(end);
NS_NAMED_LITERAL_STRING(valuePrefix, "value=");
if (FindInReadable(valuePrefix, start, end)) {
// end now points to the character after the pattern
valueStart = end;
}
</pre>
<h3 id="Memory_Allocation_-_how_to_avoid_it.2C_which_methods_to_use" name="Memory_Allocation_-_how_to_avoid_it.2C_which_methods_to_use">Memory Allocation - how to avoid it, which methods to use</h3>
<p>The preferred method to allocate a new character buffer (<code>PRUnichar*</code>/<code>char*</code>) from an existing string is with one of the following methods:</p>
<ul>
<li><code><b>PRUnichar* ToNewUnicode(
<i>
nsAString&</i>
)</b></code> - Allocates a <code>PRUnichar*</code>buffer from an <code>nsAString</code>.</li>
<li><code><b>char *ToNewCString(
<i>
nsACString&</i>
)</b></code> - Allocates a <code>char*</code>buffer from an <code>nsACString</code>. Note that this method will also work on nsAStrings, but it will do an implicit <a href="#Lossy_Conversion">lossy conversion</a>. This function should only be used if the input is known to be strictly ASCII. Often a conversion to UTF-8 is more appropriate. See <code><b>ToNewUTF8String</b></code> below.</li>
<li><code><b>char* ToNewUTF8String(
<i>
nsAString&</i>
)</b></code> - Allocates a new <code>char*</code> buffer containing the UTF-8 encoded version of the given nsAString. See <a href="#Unicode_Conversion_ns.2ACString_vs._ns.2AString">Unicode Conversion</a> for more details.</li>
</ul>
<p>These methods return a buffer allocated using XPCOM's allocator (<code>nsMemory::Alloc</code>) instead of the traditional allocator (<code>malloc</code>, etc.). You should use <code>nsMemory::Free</code> to deallocate the result when you no longer need it.</p>
<h3 id="Substrings_.28string_fragments.29" name="Substrings_.28string_fragments.29">Substrings (string fragments)</h3>
<p>It is very simple to refer to a substring of an existing string without actually allocating new space and copying the characters into that substring. <code>Substring()</code> is the preferred method to create a reference to such a string.</p>
<pre class="eval">void ProcessString(const nsAString& str) {
const nsAString& firstFive = Substring(str, 0, 5);
// firstFive is now a string representing the first 5 characters
}
</pre>
<h2 id="Unicode_Conversion_ns.2ACString_vs._ns.2AString" name="Unicode_Conversion_ns.2ACString_vs._ns.2AString">Unicode Conversion ns*CString vs. ns*String</h2>
<p>Strings can be
<i>
stored</i>
in two basic formats: 8-bit code unit (byte/<code>char</code>) strings, or 16-bit code unit (<code>PRUnichar</code>) strings. Any string class with a capital "C" in the classname contains 8-bit bytes. These classes include <code>nsCString</code>, <code>nsDependentCString</code>, and so forth. Any string class
<i>
without</i>
the "C" contains 16-bit code units.</p>
<p>A 8-bit string can be in one of many character encodings while a 16-bit string is always in UTF-16. The most common encodings are:</p>
<ul>
<li>ASCII - 8-bit encoding for basic English-only strings. Each ASCII value is stored in exactly one byte in the array.</li>
<li><a class="external" href="http://www.unicode.org/glossary/#UCS_2">UCS2</a> - 16-bit encoding for a
<i>
subset</i>
of Unicode, <a class="external" href="http://www.unicode.org/glossary/#BMP">BMP</a>. The Unicode value of a character stored in UCS2 is stored in exactly one 16-bit <code>PRUnichar</code> in a string class.</li>
<li><a class="external" href="http://www.faqs.org/rfcs/rfc3629.html">UTF-8</a> - 8-bit encoding for Unicode characters. Each Unicode characters is stored in up to 4 bytes in a string class. UTF-8 is capable of representing the entire Unicode character repertoire, and it efficiently maps to <a class="external" href="http://www.unicode.org/glossary/#UTF_32">UTF-32</a>.</li>
<li><a class="external" href="http://www.unicode.org/glossary/#UTF_16">UTF-16</a> - 16-bit encoding for Unicode storage, backwards compatible with UCS2. The Unicode value of a character stored in UTF-16 may require
<i>
one or two</i>
16-bit <code>PRUnichar</code>s in a string class. The contents of <code>nsAString</code> always has to be regarded as in this encoding instead of UCS2. UTF-16 is capable of representing the entire Unicode character repertoire, and it efficiently maps to UTF-32. (Win32 W APIs and Mac OS X natively use UTF-16.)</li>
</ul>
<p>In addition, there are literally hundreds of encodings that are provided by internationalization libraries. Access to these libraries may be part of the application (such as <code>nsICharsetConversionManager</code> in Mozilla) or built into the operating system (such as <code>iconv()</code> in UNIX operating systems and <code>MultiByteToWideChar</code>/<code>WideCharToMultiByte</code> on Windows).</p>
<p>When working with existing code, it is important to examine the current usage of the strings that you are manipulating, to determine the correct conversion mechanism.</p>
<p>When writing new code, it can be confusing to know which storage class and encoding is the most appropriate. There is no single answer to this question, but there are a few important guidelines:</p>
<ul>
<li><b>Is the string always ASCII?</b> First and foremost, you need to determine what kinds of values will be stored in the string. If the strings are always internal, ASCII strings such as "left", "true", "background" and so forth, then straight C-strings are probably the way to go.</li>
<li><b>If the string is ASCII, will it be compared to, assigned to, or otherwise interact with non-ASCII strings?</b> When assigning or comparing an 8-bit ASCII value (in)to a 16-bit UCS2 string, an "inflation" needs to happen at runtime. If your strings are small enough (say, less than 64 bytes) then it may make sense to store your string in a 16-bit unicode class as well, to avoid the extra conversion. The tradeoff is that your ASCII string takes up twice as much space as a 16-bit Unicode string than it would as an 8-bit string.</li>
<li><b>Is the string usually ASCII, but needs to support unicode?</b> If your string is most often ASCII but needs to be able to store Unicode characters, then UTF-8 may be the right encoding. ASCII characters will still be stored in 8-bit storage but other Unicode characters will take up 2 to 4 bytes. However if the string ever needs to be compared or assigned to a 16-bit string, a runtime conversion will be necessary.</li>
<li><b>Are you storing large strings of non-ASCII data?</b> Up until this point, UTF-8 might seem like the ideal encoding. The drawback is that for most non-European characters (such as Chinese, Indian and Japanese) in BMP, UTF-8 takes 50% more space than UTF-16. For characters in plane 1 and above, both UTF-8 and UTF-16 take 4 bytes.</li>
<li><b>Do you need to manipulate the contents of a Unicode string?</b> One problem with encoding Unicode characters in UTF-8 or other 8-bit storage formats is that the actual Unicode character can span multiple bytes in a string. In most encodings, the actual number of bytes varies from character to character. When you need to iterate over each character, you must take the encoding into account. This is vastly simplified when iterating 16-bit strings because each 16-bit code unit (<code>PRUnichar</code>) corresponds to a Unicode character as long as all characters are in BMP, which is often the case. However, you have to keep in mind that a single Unicode character in plane 1 and beyond is represented in two 16-bit code units in 16-bit strings so that the number of <code>PRUnichar</code>'s is
<i>
not</i>
always equal to the number of Unicode characters. For the same reason, the position and the index in terms of 16-bit code units are not always the same as the position and the index in terms of Unicode characters.</li>
</ul>
<p><br>
To assist with ASCII, UTF-8, and UTF-16 conversions, there are some helper methods and classes. Some of these classes look like functions, because they are most often used as temporary objects on the stack.</p>
<h3 id="UTF-8_.2F_UTF-16_conversion" name="UTF-8_.2F_UTF-16_conversion">UTF-8 / UTF-16 conversion</h3>
<p><code><b>NS_ConvertUTF8toUTF16(
<i>
const nsACString&</i>
)</b></code> - a <code>nsAutoString</code> subclass that converts a UTF-8 encoded <code>nsACString</code> or <code>const char*</code> to a 16-bit UTF-16 string. If you need a <code>const PRUnichar*</code> buffer, you can use the <code>.get()</code> method. For example:</p>
<pre class="eval">/* signature: void HandleUnicodeString(const nsAString& str); */
object->HandleUnicodeString(<b>NS_ConvertUTF8toUTF16</b>(utf8String));
/* signature: void HandleUnicodeBuffer(const PRUnichar* str); */
object->HandleUnicodeBuffer(<b>NS_ConvertUTF8toUTF16</b>(utf8String).get());
</pre>
<p><code><b>NS_ConvertUTF16toUTF8(
<i>
const nsAString&</i>
)</b></code> - a <code>nsCAutoString</code> which converts a 16-bit UTF-16 string (<code>nsAString</code>) to a UTF-8 encoded string. As above, you can use <code>.get()</code> to access a <code>const char*</code> buffer.</p>
<pre class="eval">/* signature: void HandleUTF8String(const nsACString& str); */
object->HandleUTF8String(<b>NS_ConvertUTF16toUTF8</b>(utf16String));
/* signature: void HandleUTF8Buffer(const char* str); */
object->HandleUTF8Buffer(<b>NS_ConvertUTF16toUTF8</b>(utf16String).get());
</pre>
<p><code><b>CopyUTF8toUTF16(
<i>
const nsACString&, nsAString&</i>
)</b></code> - converts and copies:</p>
<pre class="eval">// return a UTF-16 value
void Foo::GetUnicodeValue(nsAString& result) {
<b>CopyUTF8toUTF16</b>(mLocalUTF8Value, result);
}
</pre>
<p><code><b>AppendUTF8toUTF16(
<i>
const nsACString&, nsAString&</i>
)</b></code> - converts and appends:</p>
<pre class="eval">// return a UTF-16 value
void Foo::GetUnicodeValue(nsAString& result) {
result.AssignLiteral("prefix:");
<b>AppendUTF8toUTF16</b>(mLocalUTF8Value, result);
}
</pre>
<p><br>
<code><b>UTF8ToNewUnicode(
<i>
const nsACString&, PRUint32* aUTF16Count = nsnull</i>
)</b></code> - allocates and converts (the optional parameter will contain the number of 16-byte units upon return, if non-null):</p>
<pre class="eval">void Foo::GetUTF16Value(PRUnichar** result) {
*result = <b>UTF8ToNewUnicode</b>(mLocalUTF8Value);
}
</pre>
<p><br>
<code><b>CopyUTF16toUTF8(
<i>
const nsAString&, nsACString&</i>
)</b></code> - converts and copies:</p>
<pre class="eval">// return a UTF-8 value
void Foo::GetUTF8Value(nsACString& result) {
<b>CopyUTF16toUTF8</b>(mLocalUTF16Value, result);
}
</pre>
<p><code><b>AppendUTF16toUTF8(
<i>
const nsAString&, nsACString&</i>
)</b></code> - converts and appends:</p>
<pre class="eval">// return a UTF-8 value
void Foo::GetUnicodeValue(nsACString& result) {
result.AssignLiteral("prefix:");
<b>AppendUTF16toUTF8</b>(mLocalUTF16Value, result);
}
</pre>
<p><code><b>ToNewUTF8String(
<i>
const nsAString&</i>
)</b></code> - allocates and converts:</p>
<pre class="eval">void Foo::GetUTF8Value(char** result) {
*result = <b>ToNewUTF8String</b>(mLocalUTF16Value);
}
</pre>
<h3 id="Lossy_Conversion" name="Lossy_Conversion">Lossy Conversion</h3>
<p>The following should only be used when you can guarantee that the original string is ASCII. These helpers are very similar to the UTF-8 / UTF-16 conversion helpers above.</p>
<h4 id="UTF-16_to_ASCII_converters" name="UTF-16_to_ASCII_converters">UTF-16 to ASCII converters</h4>
<p>These converters are
<i>
<b>very dangerous</b></i>
because they
<i>
<b>lose information</b></i>
during the conversion process. You should
<i>
<b>avoid UTF-16 to ASCII conversions</b></i>
unless your strings are guaranteed to be ASCII. Each 16-bit code unit in 16-bit string is simply cast to an 8-bit byte, which means all Unicode character values above 0xFF are converted to an arbitrary 8-bit byte.</p>
<ul>
<li><code><b>NS_LossyConvertUTF16toASCII(
<i>
nsAString</i>
)</b></code> - a <code>nsCAutoString</code> which holds a temporary buffer containing the deflated value of the string.</li>
<li><code><b>LossyCopyUTF16toASCII(
<i>
nsAString, nsACString</i>
)</b></code> - does an in-place conversion from UTF-16 into an ASCII string object.</li>
<li><code><b>LossyAppendUTF16toASCII(
<i>
nsAString, nsACString</i>
)</b></code> - appends an UTF-16 string to an ASCII string, losing non-ASCII values.</li>
<li><code><b>ToNewCString(
<i>
nsAString</i>
)</b></code> - allocates a new <code>char*</code> string.</li>
</ul>
<h4 id="ASCII_to_UTF-16_converters" name="ASCII_to_UTF-16_converters">ASCII to UTF-16 converters</h4>
<p>These converters are
<i>
<b>very dangerous</b></i>
because they will
<i>
<b>mangle any non-ASCII string</b></i>
into a meaningless UTF-16 string. You should
<i>
<b>avoid ASCII to UTF-16 conversions</b></i>
unless your strings are guaranteed to be ASCII. For instance, if you have an 8-bit string encoded in a multibyte character encoding, each byte of the string will be "inflated" to a 16-bit number by simple casting.</p>
<p>For example, imagine a UTF-8 string where the first Unicode character of the string is represented with a 3-byte UTF-8 sequence, the "inflated" UTF-16 string will contain the 3 <code>PRUnichar</code>'s instead of the single <code>PRUnichar</code> that represents the first character. These <code>PRUnichar</code>'s have nothing to do with the first Unicode character in the UTF-8 string.</p>
<ul>
<li><code><b>NS_ConvertASCIItoUTF16(
<i>
nsACString</i>
)</b></code> - a <code>nsAutoString</code> which holds a temporary buffer containing the inflated value of the string.</li>
<li><code><b>CopyASCIItoUTF16(
<i>
nsACString, nsAString</i>
)</b></code> - does an in-place conversion from one string into a Unicode string object.</li>
<li><code><b>AppendASCIItoUTF16(
<i>
nsACString, nsAString</i>
)</b></code> - appends an ASCII string to a Unicode string.</li>
<li><code><b>ToNewUnicode(
<i>
nsACString</i>
)</b></code> - Creates a new <code>PRUnichar*</code> string which contains the inflated value.</li>
</ul>
<h2 id="Common_Patterns" name="Common_Patterns">Common Patterns</h2>
<h3 id="Callee-allocated_Parameters" name="Callee-allocated_Parameters">Callee-allocated Parameters</h3>
<p>Many APIs result in a method allocating a buffer in order to return strings to its caller. This can be tricky because the caller has to remember to free the string when they have finished using it. Fortunately, the <code>nsXPIDLString</code> class makes this very easy.</p>
<p>A method may look like this:</p>
<pre class="eval">void GetValue(PRUnichar** aValue)
{
*aValue = ToNewUnicode(foo);
}
</pre>
<p>Without the string classes, the caller would need to free the string:</p>
<pre>{
PRUnichar* val;
GetValue(&val);
if (someCondition) {
// don't forget to free the value!
nsMemory::Free(val);
return NS_ERROR_FAILURE;
}
...
// and later, still don't forget to free!
nsMemory::Free(val);
}
</pre>
<p>With <code>nsXPIDLString</code> you never have to worry about this. You can just use <code>getter_Copies()</code> to wrap the string class, and the class will remember to free the buffer when it goes out of scope:</p>
<pre>{
nsXPIDLString val;
GetValue(getter_Copies(val));
// val will free itself here
if (someCondition)
return NS_ERROR_FAILURE;
...
// and later, still nothing to free
}
</pre>
<p>The resulting code is much simpler, and easy to read.</p>
<h3 id="Literal_Strings" name="Literal_Strings">Literal Strings</h3>
<p>A
<i>
literal string</i>
is a raw string value that is written in some C++ code. For example, in the statement <code>printf("Hello World\n");</code> the value <code>"Hello World\n"</code> is a literal string. It is often necessary to insert literal string values when an <code>nsAString</code> or <code>nsACString</code> is required. These four macros will provide you with the necessary conversion:</p>
<ul>
<li><code><b>NS_LITERAL_CSTRING(
<i>
literal string</i>
)</b></code> - a temporary <code>nsCString</code></li>
<li><code><b>NS_NAMED_LITERAL_CSTRING(
<i>
variable,literal string</i>
)</b></code> - declares a <code>nsCString</code> variable named
<i>
variable</i>
</li>
<li><code><b>NS_LITERAL_STRING(
<i>
literal string</i>
)</b></code> - a temporary <code>nsString</code> with the unicode version of
<i>
literal string</i>
</li>
<li><code><b>NS_NAMED_LITERAL_STRING(
<i>
variable,literal string</i>
)</b></code> - declares a <code>nsString</code> variable named
<i>
variable</i>
with the unicode version of
<i>
literal string</i>
</li>
</ul>
<p>The purpose of the <code>CSTRING</code> versions of these macros may seem unnecessary, given that <code>nsDependentCString</code> will also wrap a string value in an <code>nsCString</code>. The advantage to these macros is that the length of these strings is calculated at compile time, so the string does not need to be scanned at runtime to determine its length.</p>
<p>The <code>STRING</code> versions of these macros provide a portable way of declaring UTF-16 versions of the given literal string, avoiding runtime conversion on platforms which support literal UTF-16 strings (e.g., MSVC++ and GCC with the -fshort-wchar option).</p>
<pre>// call Init(const PRUnichar*)
Init(L"start value"); // bad - L"..." is not portable!
Init(NS_ConvertASCIItoUTF16("start value").get()); // bad - runtime ASCII->UTF-16 conversion!
// call Init(const nsAString&)
Init(nsDependentString(L"start value")); // bad - not portable!
Init(NS_ConvertASCIItoUTF16("start value")); // bad - runtime ASCII->UTF-16 conversion!
// call Init(const nsACString&)
Init(nsDependentCString("start value")); // bad - length determined at runtime
</pre>
<p>Here are some examples of proper <code>NS_LITERAL_[C]STRING</code> usage.</p>
<pre>// call Init(const PRUnichar*)
Init(NS_LITERAL_STRING("start value").get());
// call Init(const nsAString&)
Init(NS_LITERAL_STRING("start value"));
// call Init(const nsACString&)
Init(NS_LITERAL_CSTRING("start value"));
</pre>
<p>There are a few details which can be useful in tracking down issues with these macros:</p>
<p><code>NS_LITERAL_STRING</code> does compile-time conversion to UTF-16 on some platforms (e.g. Windows, Linux, and Mac) but does runtime conversion on other platforms. By using <code>NS_LITERAL_STRING</code> your code is guaranteed to use the best possible conversion for the platform in question.</p>
<p>Because some platforms do runtime conversion, the use of literal string concatenation inside a <code>NS_LITERAL_STRING/NS_NAMED_LITERAL_STRING</code> macro will compile on these platforms, but not on platforms which support compile-time conversion.</p>
<p>For example:</p>
<pre>// call Init(nsAString&)
Init(NS_LITERAL_STRING("start "
"value")); // only compiles on some platforms
</pre>
<p>The reason for this is that on some platforms, the <code>L"..."</code> syntax is used, but it is only applied to the first string in the concatenation (<code>"start "</code>). When the compiler attempts to concatenate this with the non-Unicode string <code>"value"</code> it gets confused.</p>
<p>Also, using preprocessor macros as the string literal is unsupported:</p>
<pre>#define some_string "See Mozilla Run"
...
Init(NS_LITERAL_STRING( some_string )); // only compiles on some platforms/with some compilers.
</pre>
<h3 id="String_Concatenation" name="String_Concatenation">String Concatenation</h3>
<p>Strings can be concatenated together using the + operator. The resulting string is a <code>const nsSubstringTuple</code> object. The resulting object can be treated and referenced similarly to a <code>nsAString</code> object. Concatenation
<i>
does not copy the substrings</i>
. The strings are only copied when the concatenation is assigned into another string object. The <code>nsSubstringTuple</code> object holds pointers to the original strings. Therefore, the <code>nsSubstringTuple</code> object is dependent on all of its substrings, meaning that their lifetime must be at least as long as the <code>nsSubstringTuple</code> object.</p>
<p>For example, you can use the value of two strings and pass their concatenation on to another function which takes an <code>const nsAString&:</code></p>
<pre class="eval">void HandleTwoStrings(const nsAString& one, const nsAString& two) {
// call HandleString(const nsAString&)
HandleString(one + two);
}
</pre>
<p>NOTE: The two strings are implicitly combined into a temporary <code>nsString</code> in this case, and the temporary string is passed into <code>HandleString</code>. If <code>HandleString</code> assigns its input into another <code>nsString</code>, then the string buffer will be shared in this case negating the cost of the intermediate temporary. You can concatenate N strings and store the result in a temporary variable:</p>
<pre class="eval">NS_NAMED_LITERAL_STRING(start, "start ");
NS_NAMED_LITERAL_STRING(middle, "middle ");
NS_NAMED_LITERAL_STRING(end, "end");
// create a string with 3 dependent fragments - no copying involved!
nsString combinedString = start + middle + end;
// call void HandleString(const nsAString&);
HandleString(combinedString);
</pre>
<p>If you are using <code>NS_LITERAL_STRING</code> to create a temporary that is only used once, then it is safe to define it inside a concatenation because the string buffer will live as long as the temporary concatenation object (of type <code>nsSubstringTuple</code>).</p>
<pre class="eval">// call HandlePage(const nsAString&);
// safe because the concatenated-string will live as long as its substrings
HandlePage(NS_LITERAL_STRING("start ") + NS_LITERAL_STRING("end"));
</pre>
<h3 id="Local_variables" name="Local_variables">Local variables</h3>
<p>Local variables within a function are usually stored on the stack. The <code>nsAutoString/nsCAutoString</code> classes are derivatives of the <code>nsString/nsCString classes</code>. They own a 64-character buffer allocated in the same storage space as the string itself. If the <code>nsAutoString</code> is allocated on the stack, then it has at its disposal a 64-character stack buffer. This allows the implementation to avoid allocating extra memory when dealing with small strings.</p>
<pre class="eval">...
nsAutoString value;
GetValue(value); // if the result is less than 64 code units,
// then this just saved us an allocation
...
</pre>
<h3 id="Member_variables" name="Member_variables">Member variables</h3>
<p>In general, you should use the concrete classes <code>nsString</code> and <code>nsCString</code> for member variables.</p>
<pre class="eval">class Foo {
...
// these store UTF-8 and UTF-16 values respectively
nsCString mLocalName;
nsString mTitle;
};
</pre>
<p>Note that the strings are declared directly in the class, not as pointers to strings. Don't do this:</p>
<pre>class Foo {
public:
Foo() {
mLocalName = new nsCString();
mTitle = new nsString();
}
~Foo() { delete mLocalName; delete mTitle; }
private:
// these store UTF-8 and UTF-16 values respectively
nsCString* mLocalName;
nsString* mTitle;
};
</pre>
<p>The above code may appear to save the cost of the string objects, but <code>nsString/nsCString</code> are small objects - the overhead of the allocation outweighs the few bytes you'd save by keeping a pointer.</p>
<p>Another common incorrect pattern is to use <code>nsAutoString/nsCAutoString</code> for member variables. As described in <a href="#Local_variables">Local Variables</a>, these classes have a built in buffer that make them very large. This means that if you include them in a class, they bloat the class by 64 bytes (<code>nsCAutoString</code>) or 128 bytes (<code>nsAutoString</code>).</p>
<p>An example:</p>
<pre>class Foo {
...
// bloats 'Foo' by 128 bytes!
nsAutoString mLocalName;
};
</pre>
<h3 id="Raw_Character_Pointers" name="Raw_Character_Pointers">Raw Character Pointers</h3>
<p><code>PromiseFlatString()</code> can be used to create a temporary buffer which holds a null-terminated buffer containing the same value as the source string. <code>PromiseFlatString()</code> will create a temporary buffer if necessary. This is most often used in order to pass an <code>nsAString</code> to an API which requires a null-terminated string.</p>
<p>In the following example, an <code>nsAString</code> is combined with a literal string, and the result is passed to an API which requires a simple character buffer.</p>
<pre class="eval">// Modify the URL and pass to AddPage(const PRUnichar* url)
void AddModifiedPage(const nsAString& url) {
NS_NAMED_LITERAL_STRING(httpPrefix, <span class="nowiki">"http://"</span>);
const nsAString& modifiedURL = httpPrefix + url;
// creates a temporary buffer
AddPage(PromiseFlatString(modifiedURL).get());
}
</pre>
<p><code>PromiseFlatString()</code> is smart when handed a string that is already null-terminated. It avoids creating the temporary buffer in such cases.</p>
<pre class="eval">// Modify the URL and pass to AddPage(const PRUnichar* url)
void AddModifiedPage(const nsAString& url, PRBool addPrefix) {
if (addPrefix) {
// MUST create a temporary buffer - string is multi-fragmented
NS_NAMED_LITERAL_STRING(httpPrefix, <span class="nowiki">"http://"</span>);
AddPage(PromiseFlatString(httpPrefix + modifiedURL));
} else {
// MIGHT create a temporary buffer, does a runtime check
AddPage(PromiseFlatString(url).get());
}
}
</pre>
<h3 id="printf_and_a_UTF-16_string" name="printf_and_a_UTF-16_string"><code>printf</code> and a UTF-16 string</h3>
<p>For debugging, it's useful to <code>printf</code> a UTF-16 string (nsString, nsAutoString, nsXPIDLString, etc). To do this usually requires converting it to an 8-bit string, because that's what printf expects. However, on Windows, the following should work:</p>
<pre class="eval">printf("%S\n", yourString.get());
</pre>
<p>(Note: I didn't test this. Also, I'm not sure what exactly this does to non-ASCII characters, especially when they are outside the system codepage). The reason that this doesn't work on Unix is because a wchar_t, which is what %S expects, is usually 4 bytes there (even when Mozilla is compiled with -fshort-wchar, because this would require libc to be compiled with -fshort-wchar).</p>
<p>If non-ASCII characters aren't important, use:</p>
<pre class="eval">printf("%s\n", NS_LossyConvertUTF16toASCII(yourString).get());
</pre>
<p>On platforms that use UTF-8 for console output (most Linux distributions), this works:</p>
<pre class="eval">printf("%s\n", NS_ConvertUTF16toUTF8(yourString).get());
</pre>
<h2 id="IDL" name="IDL">IDL</h2>
<p>The string library is also available through IDL. By declaring attributes and methods using the specially defined IDL types, string classes are used as parameters to the corresponding methods.</p>
<h3 id="IDL_String_types" name="IDL_String_types">IDL String types</h3>
<p>The C++ signatures follow the abstract-type convention described above, such that all method parameters are based on the <a href="#The_Abstract_Classes">abstract classes</a>. The following table describes the purpose of each string type in IDL.</p>
<table class="standard-table">
<tbody>
<tr>
<th class="header">IDL type</th>
<th class="header">C++ Type</th>
<th class="header">Purpose</th>
</tr>
<tr>
<td><code>string</code></td>
<td><code>char*</code></td>
<td>Raw character pointer to ASCII (7-bit) string, no string classes used. High bit is not guaranteed across XPConnect boundaries</td>
</tr>
<tr>
<td><code>wstring</code></td>
<td><code>PRUnichar*</code></td>
<td>Raw character pointer to UTF-16 string, no string classes used</td>
</tr>
<tr>
<td><code>AString</code></td>
<td><code>nsAString</code></td>
<td>UTF-16 string</td>
</tr>
<tr>
<td><code>ACString</code></td>
<td><code>nsACString</code></td>
<td>8-bit string, all bits are preserved across XPConnect boundaries</td>
</tr>
<tr>
<td><code>AUTF8String</code></td>
<td><code>nsACString</code></td>
<td>UTF-8 string - converted to UTF-16 as necessary when value is used across XPConnect boundaries</td>
</tr>
<tr>
<td><code>DOMString</code></td>
<td><code>nsAString</code></td>
<td>UTF-16 string used in the DOM. More or less the same as <code>AString</code>, but in JavaScript it has no distinction between whether the string is void or just empty. (not sure on this, looking for corrections.</td>
</tr>
</tbody>
</table>
<h3 id="C.2B.2B_Signatures" name="C.2B.2B_Signatures">C++ Signatures</h3>
<p>In IDL, <code>in</code> parameters are read-only, and the C++ signatures for <code>*String</code> parameters follows the above guidelines by using <code>const nsAString&</code> for these parameters. <code>out</code> and <code>inout</code> parameters are defined simply as <code>nsAString</code> so that the callee can write to them.</p>
<table class="standard-table">
<tbody>
<tr>
<th class="header">IDL</th>
<th class="header">C++</th>
</tr>
<tr>
<td>
<pre class="eval">
interface nsIFoo : nsISupports {
attribute AString utf16String;
AUTF8String getValue(in ACString key);
};
</pre>
</td>
<td>
<pre class="eval">
class nsIFoo : public nsISupports {
NS_IMETHOD GetUtf16String(nsAString&
aResult) = 0;
NS_IMETHOD SetUtf16String(const nsAString&
aValue) = 0;
NS_IMETHOD GetValue(const nsACString& aKey,
nsACString& aResult) = 0;
};
</pre>
</td>
</tr>
</tbody>
</table>
<p>In the above example, <code>utf16String</code> is treated as a UTF-16 string. The implementation of <code>GetUtf16String()</code> will use <code>aResult.Assign</code> to "return" the value. In <code>SetUtf16String()</code> the value of the string can be used through a variety of methods including <a href="#Iterators">Iterators</a>, <code><a href="#Raw_Character_Pointers">PromiseFlatString</a></code>, and assignment to other strings.</p>
<p>In <code>GetValue()</code>, the first parameter, <code>aKey</code>, is treated as a raw sequence of 8-bit values. Any non-ASCII characters in <code>aKey</code> will be preserved when crossing XPConnect boundaries. The implementation of <code>GetValue()</code> will assign a UTF-8 encoded 8-bit string into <code>aResult</code>. If the <code>this</code> method is called across XPConnect boundaries, such as from a script, then the result will be decoded from UTF-8 into UTF-16 and used as a Unicode value.</p>
<h3 id="Choosing_a_string_type" name="Choosing_a_string_type">Choosing a string type</h3>
<p>It can be difficult to determine the correct string type to use for IDL. The following points should help determine the appropriate string type.</p>
<ul>
<li>Using string classes may avoid new memory allocation for <code>out</code> parameters. For example, if the caller is using an <code>nsAutoString</code> to receive the value for an <code>out</code> parameter, (defined in C++ as simply <code>nsAString&</code> then assignment of short (less than 64-characters) values to an <code>out</code> parameter will only copy the value into the <code>nsAutoString</code>'s buffer. Moreover, using the string classes allows for sharing of string buffers. In many cases, assigning from one string object to another avoids copying in favor of simply incrementing a reference count.</li>
<li><code>in</code> strings using string classes often have their length pre-calculated. This can be a performance win.</li>
<li>In cases where a raw-character buffer is required, <code>string</code> and <code>wstring</code> provide faster access than <code>PromiseFlatString</code>.</li>
<li>UTF-8 strings defined with <code>AUTF8String</code> may need to be decoded when crossing XPConnect boundaries. This can be a performance hit. On the other hand, UTF-8 strings take up less space for strings that are commonly ASCII.</li>
<li>UTF-16 strings defined with <code>wstring</code> or <code>AString</code> are fast when the unicode value is required. However, if the value is more often ASCII, then half of the storage space of the underlying string may be wasted.</li>
</ul>
<h2 id="Appendix_A_-_What_class_to_use_when" name="Appendix_A_-_What_class_to_use_when">Appendix A - What class to use when</h2>
<p>This table provides a quick reference for what classes you should be using.</p>
<table class="standard-table">
<tbody>
<tr>
<th class="header">Context</th>
<th class="header">class</th>
<th class="header">Notes</th>
</tr>
<tr>
<td>Local Variables</td>
<td><code>nsAutoString<br>
nsCAutoString</code></td>
<td> </td>
</tr>
<tr>
<td>Class Member Variables</td>
<td><code>nsString<br>
nsCString</code></td>
<td> </td>
</tr>
<tr>
<td>Method Parameter types</td>
<td><code>nsAString<br>
nsACString</code></td>
<td>Use abstract classes for parameters. Use <code>const nsAString&</code> for "in" parameters and <code>nsAString&</code> for "out" parameters.</td>
</tr>
<tr>
<td>Retrieving "out" string/wstrings</td>
<td><code>nsXPIDLString<br>
nsXPIDLCString</code></td>
<td>Use <code>getter_Copies()</code>. Similar to <code>nsString / nsCString</code>.</td>
</tr>
<tr>
<td>Wrapping character buffers</td>
<td><code>nsDependentString<br>
nsDependentCString</code></td>
<td>Wrap <code>const char* / const PRUnichar*</code> buffers.</td>
</tr>
<tr>
<td>Literal strings</td>
<td><code>NS_LITERAL_STRING<br>
NS_LITERAL_CSTRING</code></td>
<td>Similar to <code>nsDependent[C]String</code>, but pre-calculates length at build time.</td>
</tr>
</tbody>
</table>
<h2 id="Appendix_B_-_nsAString_Reference" name="Appendix_B_-_nsAString_Reference">Appendix B - nsAString Reference</h2>
<p>Read-only methods.</p>
<ul>
<li><code><b>Length()</b></code></li>
<li><code><b>IsEmpty()</b></code></li>
<li><code><b>IsVoid()</b></code> - XPConnect will convert void nsAStrings to JavaScript <code>null</code>.</li>
<li><code><b>BeginReading(
<i>
iterator</i>
)</b></code></li>
<li><code><b>EndReading(
<i>
iterator</i>
)</b></code></li>
<li><code><b>Equals(
<i>
string[, comparator]</i>
)</b></code></li>
<li><code><b>First()</b></code></li>
<li><code><b>Last()</b></code></li>
<li><code><b>CountChar()</b></code></li>
<li><code><b>Left(
<i>
outstring, length</i>
)</b></code></li>
<li><code><b>Mid(
<i>
outstring, position, length</i>
)</b></code></li>
<li><code><b>Right(
<i>
outstring, length</i>
)</b></code></li>
<li><code><b>FindChar(
<i>
character</i>
)</b></code></li>
</ul>
<p>Methods that modify the string.</p>
<ul>
<li><code><b>Assign(
<i>
string</i>
)</b></code></li>
<li><code><b>Append(
<i>
string</i>
)</b></code></li>
<li><code><b>Insert(
<i>
string</i>
)</b></code></li>
<li><code><b>Cut(
<i>
start, length</i>
)</b></code></li>
<li><code><b>Replace(
<i>
start, length, string</i>
)</b></code></li>
<li><code><b>Truncate(
<i>
length</i>
)</b></code></li>
<li><code><b>SetIsVoid(
<i>
state</i>
)</b></code> - XPConnect will convert void nsAStrings to JavaScript <code>null</code>.</li>
<li><code><b>BeginWriting(
<i>
iterator</i>
)</b></code></li>
<li><code><b>EndWriting(
<i>
iterator</i>
)</b></code></li>
<li><code><b>SetCapacity()</b></code></li>
</ul>
|