1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef ProfileBufferEntrySerializationGeckoExtensions_h
8 #define ProfileBufferEntrySerializationGeckoExtensions_h
9 
10 #include "mozilla/ProfileBufferEntrySerialization.h"
11 
12 #include "js/AllocPolicy.h"
13 #include "js/Utility.h"
14 #include "nsString.h"
15 
16 namespace mozilla {
17 
18 // ----------------------------------------------------------------------------
19 // ns[C]String
20 
21 // nsString or nsCString contents are serialized as the number of bytes (encoded
22 // as ULEB128) and all the characters in the string. The terminal '\0' is
23 // omitted.
24 // Make sure you write and read with the same character type!
25 //
26 // Usage: `nsCString s = ...; aEW.WriteObject(s);`
27 template <typename T>
28 struct ProfileBufferEntryWriter::Serializer<nsTString<T>> {
29   static Length Bytes(const nsTString<T>& aS) {
30     // Note that we store the size in *bytes*, not in number of characters.
31     const auto bytes = aS.Length() * sizeof(T);
32     return ProfileBufferEntryWriter::ULEB128Size(bytes) +
33            static_cast<Length>(bytes);
34   }
35 
36   static void Write(ProfileBufferEntryWriter& aEW, const nsTString<T>& aS) {
37     // Note that we store the size in *bytes*, not in number of characters.
38     const auto bytes = aS.Length() * sizeof(T);
39     aEW.WriteULEB128(bytes);
40     // Copy the bytes from the string's buffer.
41     aEW.WriteBytes(reinterpret_cast<const char*>(aS.BeginReading()), bytes);
42   }
43 };
44 
45 template <typename T>
46 struct ProfileBufferEntryReader::Deserializer<nsTString<T>> {
47   static void ReadInto(ProfileBufferEntryReader& aER, nsTString<T>& aS) {
48     aS = Read(aER);
49   }
50 
51   static nsTString<T> Read(ProfileBufferEntryReader& aER) {
52     // Note that the stored size is in *bytes*, not in number of characters.
53     const auto bytes = aER.ReadULEB128<Length>();
54     nsTString<T> s;
55     nsresult rv;
56     // BulkWrite is the most efficient way to copy bytes into the target string.
57     auto writer = s.BulkWrite(bytes / sizeof(T), 0, true, rv);
58     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
59     aER.ReadBytes(reinterpret_cast<char*>(writer.Elements()), bytes);
60     writer.Finish(bytes / sizeof(T), true);
61     return s;
62   }
63 };
64 
65 // ----------------------------------------------------------------------------
66 // nsAuto[C]String
67 
68 // nsAuto[C]String contents are serialized as the number of bytes (encoded as
69 // ULEB128) and all the characters in the string. The terminal '\0' is omitted.
70 // Make sure you write and read with the same character type!
71 //
72 // Usage: `nsAutoCString s = ...; aEW.WriteObject(s);`
73 template <typename T, size_t N>
74 struct ProfileBufferEntryWriter::Serializer<nsTAutoStringN<T, N>> {
75   static Length Bytes(const nsTAutoStringN<T, N>& aS) {
76     // Note that we store the size in *bytes*, not in number of characters.
77     const auto bytes = aS.Length() * sizeof(T);
78     return ProfileBufferEntryWriter::ULEB128Size(bytes) +
79            static_cast<Length>(bytes);
80   }
81 
82   static void Write(ProfileBufferEntryWriter& aEW,
83                     const nsTAutoStringN<T, N>& aS) {
84     const auto bytes = aS.Length() * sizeof(T);
85     // Note that we store the size in *bytes*, not in number of characters.
86     aEW.WriteULEB128(bytes);
87     // Copy the bytes from the string's buffer.
88     aEW.WriteBytes(reinterpret_cast<const char*>(aS.BeginReading()), bytes);
89   }
90 };
91 
92 template <typename T, size_t N>
93 struct ProfileBufferEntryReader::Deserializer<nsTAutoStringN<T, N>> {
94   static void ReadInto(ProfileBufferEntryReader& aER,
95                        nsTAutoStringN<T, N>& aS) {
96     aS = Read(aER);
97   }
98 
99   static nsTAutoStringN<T, N> Read(ProfileBufferEntryReader& aER) {
100     // Note that the stored size is in *bytes*, not in number of characters.
101     const auto bytes = aER.ReadULEB128<Length>();
102     nsTAutoStringN<T, N> s;
103     nsresult rv;
104     // BulkWrite is the most efficient way to copy bytes into the target string.
105     auto writer = s.BulkWrite(bytes / sizeof(T), 0, true, rv);
106     MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
107     aER.ReadBytes(reinterpret_cast<char*>(writer.Elements()), bytes);
108     writer.Finish(bytes / sizeof(T), true);
109     return s;
110   }
111 };
112 
113 // ----------------------------------------------------------------------------
114 // JS::UniqueChars
115 
116 // JS::UniqueChars contents are serialized as the number of bytes (encoded as
117 // ULEB128) and all the characters in the string. The terminal '\0' is omitted.
118 // Note: A nullptr pointer will be serialized like an empty string, so when
119 // deserializing it will result in an allocated buffer only containing a
120 // single null terminator.
121 //
122 // Usage: `JS::UniqueChars s = ...; aEW.WriteObject(s);`
123 template <>
124 struct ProfileBufferEntryWriter::Serializer<JS::UniqueChars> {
125   static Length Bytes(const JS::UniqueChars& aS) {
126     if (!aS) {
127       return ProfileBufferEntryWriter::ULEB128Size<Length>(0);
128     }
129     const auto len = static_cast<Length>(strlen(aS.get()));
130     return ProfileBufferEntryWriter::ULEB128Size(len) + len;
131   }
132 
133   static void Write(ProfileBufferEntryWriter& aEW, const JS::UniqueChars& aS) {
134     if (!aS) {
135       aEW.WriteULEB128<Length>(0);
136       return;
137     }
138     const auto len = static_cast<Length>(strlen(aS.get()));
139     aEW.WriteULEB128(len);
140     aEW.WriteBytes(aS.get(), len);
141   }
142 };
143 
144 template <>
145 struct ProfileBufferEntryReader::Deserializer<JS::UniqueChars> {
146   static void ReadInto(ProfileBufferEntryReader& aER, JS::UniqueChars& aS) {
147     aS = Read(aER);
148   }
149 
150   static JS::UniqueChars Read(ProfileBufferEntryReader& aER) {
151     const auto len = aER.ReadULEB128<Length>();
152     // Use the same allocation policy as JS_smprintf.
153     char* buffer =
154         static_cast<char*>(js::SystemAllocPolicy{}.pod_malloc<char>(len + 1));
155     aER.ReadBytes(buffer, len);
156     buffer[len] = '\0';
157     return JS::UniqueChars(buffer);
158   }
159 };
160 
161 }  // namespace mozilla
162 
163 #endif  // ProfileBufferEntrySerializationGeckoExtensions_h
164