blob: a011cd553d0c5cc262d15748d804df5f751f21a6 [file] [log] [blame]
Enrico Granataca6c8ee2014-10-30 01:45:39 +00001//===-- StringPrinter.cpp ----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/DataFormatters/StringPrinter.h"
11
12#include "lldb/Core/DataExtractor.h"
Enrico Granataebdc1ac2014-11-05 21:20:48 +000013#include "lldb/Core/Debugger.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000014#include "lldb/Core/Error.h"
Enrico Granataebdc1ac2014-11-05 21:20:48 +000015#include "lldb/Core/ValueObject.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000016#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
18
19#include "llvm/Support/ConvertUTF.h"
20
Enrico Granataca6c8ee2014-10-30 01:45:39 +000021#include <ctype.h>
22#include <functional>
23#include <locale>
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::formatters;
28
29// I can't use a std::unique_ptr for this because the Deleter is a template argument there
30// and I want the same type to represent both pointers I want to free and pointers I don't need
31// to free - which is what this class essentially is
32// It's very specialized to the needs of this file, and not suggested for general use
33template <typename T = uint8_t, typename U = char, typename S = size_t>
34struct StringPrinterBufferPointer
35{
36public:
37
38 typedef std::function<void(const T*)> Deleter;
39
40 StringPrinterBufferPointer (std::nullptr_t ptr) :
41 m_data(nullptr),
42 m_size(0),
43 m_deleter()
44 {}
45
46 StringPrinterBufferPointer(const T* bytes, S size, Deleter deleter = nullptr) :
47 m_data(bytes),
48 m_size(size),
49 m_deleter(deleter)
50 {}
51
52 StringPrinterBufferPointer(const U* bytes, S size, Deleter deleter = nullptr) :
53 m_data((T*)bytes),
54 m_size(size),
55 m_deleter(deleter)
56 {}
57
58 StringPrinterBufferPointer(StringPrinterBufferPointer&& rhs) :
59 m_data(rhs.m_data),
60 m_size(rhs.m_size),
61 m_deleter(rhs.m_deleter)
62 {
63 rhs.m_data = nullptr;
64 }
65
66 StringPrinterBufferPointer(const StringPrinterBufferPointer& rhs) :
67 m_data(rhs.m_data),
68 m_size(rhs.m_size),
69 m_deleter(rhs.m_deleter)
70 {
71 rhs.m_data = nullptr; // this is why m_data has to be mutable
72 }
73
74 const T*
75 GetBytes () const
76 {
77 return m_data;
78 }
79
80 const S
81 GetSize () const
82 {
83 return m_size;
84 }
85
86 ~StringPrinterBufferPointer ()
87 {
88 if (m_data && m_deleter)
89 m_deleter(m_data);
90 m_data = nullptr;
91 }
92
93 StringPrinterBufferPointer&
94 operator = (const StringPrinterBufferPointer& rhs)
95 {
96 if (m_data && m_deleter)
97 m_deleter(m_data);
98 m_data = rhs.m_data;
99 m_size = rhs.m_size;
100 m_deleter = rhs.m_deleter;
101 rhs.m_data = nullptr;
102 return *this;
103 }
104
105private:
106 mutable const T* m_data;
107 size_t m_size;
108 Deleter m_deleter;
109};
110
111// we define this for all values of type but only implement it for those we care about
112// that's good because we get linker errors for any unsupported type
113template <StringElementType type>
114static StringPrinterBufferPointer<>
115GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
116
117// mimic isprint() for Unicode codepoints
118static bool
119isprint(char32_t codepoint)
120{
121 if (codepoint <= 0x1F || codepoint == 0x7F) // C0
122 {
123 return false;
124 }
125 if (codepoint >= 0x80 && codepoint <= 0x9F) // C1
126 {
127 return false;
128 }
129 if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators
130 {
131 return false;
132 }
133 if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control
134 {
135 return false;
136 }
137 if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials
138 {
139 return false;
140 }
141 return true;
142}
143
144template <>
145StringPrinterBufferPointer<>
146GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
147{
148 StringPrinterBufferPointer<> retval = {nullptr};
149
150 switch (*buffer)
151 {
Enrico Granatada04fbb2014-12-18 19:43:29 +0000152 case 0:
153 retval = {"\\0",2};
154 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000155 case '\a':
156 retval = {"\\a",2};
157 break;
158 case '\b':
159 retval = {"\\b",2};
160 break;
161 case '\f':
162 retval = {"\\f",2};
163 break;
164 case '\n':
165 retval = {"\\n",2};
166 break;
167 case '\r':
168 retval = {"\\r",2};
169 break;
170 case '\t':
171 retval = {"\\t",2};
172 break;
173 case '\v':
174 retval = {"\\v",2};
175 break;
176 case '\"':
177 retval = {"\\\"",2};
178 break;
179 case '\\':
180 retval = {"\\\\",2};
181 break;
182 default:
183 if (isprint(*buffer))
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000184 retval = {buffer,1};
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000185 else
186 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000187 uint8_t* data = new uint8_t[5];
188 sprintf((char*)data,"\\x%02x",*buffer);
189 retval = {data, 4, [] (const uint8_t* c) {delete[] c;} };
190 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000191 }
192 }
193
194 next = buffer + 1;
195 return retval;
196}
197
198static char32_t
199ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1)
200{
201 return (c0-192)*64+(c1-128);
202}
203static char32_t
204ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2)
205{
206 return (c0-224)*4096+(c1-128)*64+(c2-128);
207}
208static char32_t
209ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3)
210{
211 return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128);
212}
213
214template <>
215StringPrinterBufferPointer<>
216GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
217{
218 StringPrinterBufferPointer<> retval {nullptr};
219
220 unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer);
221
222 if (1+buffer_end-buffer < utf8_encoded_len)
223 {
224 // I don't have enough bytes - print whatever I have left
225 retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)};
226 next = buffer_end+1;
227 return retval;
228 }
229
230 char32_t codepoint = 0;
231 switch (utf8_encoded_len)
232 {
233 case 1:
234 // this is just an ASCII byte - ask ASCII
235 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
236 case 2:
237 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1));
238 break;
239 case 3:
240 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2));
241 break;
242 case 4:
243 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3));
244 break;
245 default:
246 // this is probably some bogus non-character thing
247 // just print it as-is and hope to sync up again soon
248 retval = {buffer,1};
249 next = buffer+1;
250 return retval;
251 }
252
253 if (codepoint)
254 {
255 switch (codepoint)
256 {
Enrico Granatada04fbb2014-12-18 19:43:29 +0000257 case 0:
258 retval = {"\\0",2};
259 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000260 case '\a':
261 retval = {"\\a",2};
262 break;
263 case '\b':
264 retval = {"\\b",2};
265 break;
266 case '\f':
267 retval = {"\\f",2};
268 break;
269 case '\n':
270 retval = {"\\n",2};
271 break;
272 case '\r':
273 retval = {"\\r",2};
274 break;
275 case '\t':
276 retval = {"\\t",2};
277 break;
278 case '\v':
279 retval = {"\\v",2};
280 break;
281 case '\"':
282 retval = {"\\\"",2};
283 break;
284 case '\\':
285 retval = {"\\\\",2};
286 break;
287 default:
288 if (isprint(codepoint))
289 retval = {buffer,utf8_encoded_len};
290 else
291 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000292 uint8_t* data = new uint8_t[11];
293 sprintf((char*)data,"\\U%08x",codepoint);
294 retval = { data,10,[] (const uint8_t* c) {delete[] c;} };
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000295 break;
296 }
297 }
298
299 next = buffer + utf8_encoded_len;
300 return retval;
301 }
302
303 // this should not happen - but just in case.. try to resync at some point
304 retval = {buffer,1};
305 next = buffer+1;
306 return retval;
307}
308
309// Given a sequence of bytes, this function returns:
310// a sequence of bytes to actually print out + a length
311// the following unscanned position of the buffer is in next
312static StringPrinterBufferPointer<>
313GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
314{
315 if (!buffer)
316 return {nullptr};
317
318 switch (type)
319 {
320 case StringElementType::ASCII:
321 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next);
322 case StringElementType::UTF8:
323 return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next);
324 default:
325 return {nullptr};
326 }
327}
328
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000329// use this call if you already have an LLDB-side buffer for the data
330template<typename SourceDataType>
331static bool
332DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
333 const SourceDataType*,
334 UTF8**,
335 UTF8*,
336 ConversionFlags),
337 const DataExtractor& data,
338 Stream& stream,
339 char prefix_token,
340 char quote,
341 uint32_t sourceSize,
342 bool escapeNonPrintables)
343{
344 if (prefix_token != 0)
345 stream.Printf("%c",prefix_token);
346 if (quote != 0)
347 stream.Printf("%c",quote);
348 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
349 {
350 const int bufferSPSize = data.GetByteSize();
351 if (sourceSize == 0)
352 {
353 const int origin_encoding = 8*sizeof(SourceDataType);
354 sourceSize = bufferSPSize/(origin_encoding / 4);
355 }
356
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000357 const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart();
358 const SourceDataType *data_end_ptr = data_ptr + sourceSize;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000359
360 while (data_ptr < data_end_ptr)
361 {
362 if (!*data_ptr)
363 {
364 data_end_ptr = data_ptr;
365 break;
366 }
367 data_ptr++;
368 }
369
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000370 data_ptr = (const SourceDataType*)data.GetDataStart();
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000371
372 lldb::DataBufferSP utf8_data_buffer_sp;
373 UTF8* utf8_data_ptr = nullptr;
374 UTF8* utf8_data_end_ptr = nullptr;
375
376 if (ConvertFunction)
377 {
378 utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0));
379 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
380 utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000381 ConvertFunction ( &data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000382 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
383 }
384 else
385 {
386 // just copy the pointers - the cast is necessary to make the compiler happy
387 // but this should only happen if we are reading UTF8 data
388 utf8_data_ptr = (UTF8*)data_ptr;
389 utf8_data_end_ptr = (UTF8*)data_end_ptr;
390 }
391
392 // since we tend to accept partial data (and even partially malformed data)
393 // we might end up with no NULL terminator before the end_ptr
394 // hence we need to take a slower route and ensure we stay within boundaries
395 for (;utf8_data_ptr < utf8_data_end_ptr;)
396 {
397 if (!*utf8_data_ptr)
398 break;
399
400 if (escapeNonPrintables)
401 {
402 uint8_t* next_data = nullptr;
403 auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data);
404 auto printable_bytes = printable.GetBytes();
405 auto printable_size = printable.GetSize();
406 if (!printable_bytes || !next_data)
407 {
408 // GetPrintable() failed on us - print one byte in a desperate resync attempt
409 printable_bytes = utf8_data_ptr;
410 printable_size = 1;
411 next_data = utf8_data_ptr+1;
412 }
Andy Gibbs3acfe1a2014-12-29 13:03:19 +0000413 for (unsigned c = 0; c < printable_size; c++)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000414 stream.Printf("%c", *(printable_bytes+c));
415 utf8_data_ptr = (uint8_t*)next_data;
416 }
417 else
418 {
419 stream.Printf("%c",*utf8_data_ptr);
420 utf8_data_ptr++;
421 }
422 }
423 }
424 if (quote != 0)
425 stream.Printf("%c",quote);
426 return true;
427}
428
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000429lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
430 ReadStringAndDumpToStreamOptions()
431{
432 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
433}
434
435lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
436 ReadBufferAndDumpToStreamOptions()
437{
438 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
439}
440
441
Shawn Bestfd137432014-11-04 22:43:34 +0000442namespace lldb_private
443{
444
445namespace formatters
446{
447
448template <>
449bool
450ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options)
451{
452 assert(options.GetStream() && "need a Stream to print the string to");
453 Error my_error;
Shawn Bestfd137432014-11-04 22:43:34 +0000454
455 ProcessSP process_sp(options.GetProcessSP());
456
457 if (process_sp.get() == nullptr || options.GetLocation() == 0)
458 return false;
459
460 size_t size;
461
462 if (options.GetSourceSize() == 0)
463 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
Enrico Granata34042212014-11-18 22:54:45 +0000464 else if (!options.GetIgnoreMaxLength())
Shawn Bestfd137432014-11-04 22:43:34 +0000465 size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary());
Enrico Granata34042212014-11-18 22:54:45 +0000466 else
467 size = options.GetSourceSize();
Shawn Bestfd137432014-11-04 22:43:34 +0000468
469 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
470
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000471 process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
Shawn Bestfd137432014-11-04 22:43:34 +0000472
473 if (my_error.Fail())
474 return false;
475
476 char prefix_token = options.GetPrefixToken();
477 char quote = options.GetQuote();
478
479 if (prefix_token != 0)
480 options.GetStream()->Printf("%c%c",prefix_token,quote);
481 else if (quote != 0)
482 options.GetStream()->Printf("%c",quote);
483
484 uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize();
485
486 // since we tend to accept partial data (and even partially malformed data)
487 // we might end up with no NULL terminator before the end_ptr
488 // hence we need to take a slower route and ensure we stay within boundaries
489 for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);)
490 {
491 if (options.GetEscapeNonPrintables())
492 {
493 uint8_t* next_data = nullptr;
494 auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data);
495 auto printable_bytes = printable.GetBytes();
496 auto printable_size = printable.GetSize();
497 if (!printable_bytes || !next_data)
498 {
499 // GetPrintable() failed on us - print one byte in a desperate resync attempt
500 printable_bytes = data;
501 printable_size = 1;
502 next_data = data+1;
503 }
Andy Gibbs3acfe1a2014-12-29 13:03:19 +0000504 for (unsigned c = 0; c < printable_size; c++)
Shawn Bestfd137432014-11-04 22:43:34 +0000505 options.GetStream()->Printf("%c", *(printable_bytes+c));
506 data = (uint8_t*)next_data;
507 }
508 else
509 {
510 options.GetStream()->Printf("%c",*data);
511 data++;
512 }
513 }
514
515 if (quote != 0)
516 options.GetStream()->Printf("%c",quote);
517
518 return true;
519}
520
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000521template<typename SourceDataType>
522static bool
523ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
524 ConversionResult (*ConvertFunction) (const SourceDataType**,
525 const SourceDataType*,
526 UTF8**,
527 UTF8*,
528 ConversionFlags))
529{
530 assert(options.GetStream() && "need a Stream to print the string to");
531
532 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
533 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000534
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000535 lldb::ProcessSP process_sp(options.GetProcessSP());
Shawn Bestfd137432014-11-04 22:43:34 +0000536
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000537 if (!process_sp)
538 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000539
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000540 const int type_width = sizeof(SourceDataType);
541 const int origin_encoding = 8 * type_width ;
542 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
543 return false;
544 // if not UTF8, I need a conversion function to return proper UTF8
545 if (origin_encoding != 8 && !ConvertFunction)
546 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000547
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000548 if (!options.GetStream())
549 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000550
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000551 uint32_t sourceSize = options.GetSourceSize();
552 bool needs_zero_terminator = options.GetNeedsZeroTermination();
Shawn Bestfd137432014-11-04 22:43:34 +0000553
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000554 if (!sourceSize)
555 {
556 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
557 needs_zero_terminator = true;
558 }
Enrico Granatab0e8a552015-05-01 22:57:38 +0000559 else if (!options.GetIgnoreMaxLength())
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000560 sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
Shawn Bestfd137432014-11-04 22:43:34 +0000561
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000562 const int bufferSPSize = sourceSize * type_width;
Shawn Bestfd137432014-11-04 22:43:34 +0000563
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000564 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
Shawn Bestfd137432014-11-04 22:43:34 +0000565
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000566 if (!buffer_sp->GetBytes())
567 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000568
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000569 Error error;
570 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
Shawn Bestfd137432014-11-04 22:43:34 +0000571
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000572 if (needs_zero_terminator)
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000573 process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000574 else
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000575 process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
Shawn Bestfd137432014-11-04 22:43:34 +0000576
Enrico Granata099263b2014-11-17 23:14:11 +0000577 if (error.Fail())
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000578 {
579 options.GetStream()->Printf("unable to read data");
580 return true;
581 }
Shawn Bestfd137432014-11-04 22:43:34 +0000582
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000583 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
Shawn Bestfd137432014-11-04 22:43:34 +0000584
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000585 return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables());
586}
587
588template <>
589bool
Shawn Bestfd137432014-11-04 22:43:34 +0000590ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000591{
592 return ReadUTFBufferAndDumpToStream<UTF8>(options,
593 nullptr);
594}
595
596template <>
597bool
Shawn Bestfd137432014-11-04 22:43:34 +0000598ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000599{
600 return ReadUTFBufferAndDumpToStream<UTF16>(options,
601 ConvertUTF16toUTF8);
602}
603
604template <>
605bool
Shawn Bestfd137432014-11-04 22:43:34 +0000606ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000607{
608 return ReadUTFBufferAndDumpToStream<UTF32>(options,
609 ConvertUTF32toUTF8);
610}
611
612template <>
613bool
Shawn Bestfd137432014-11-04 22:43:34 +0000614ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000615{
616 assert(options.GetStream() && "need a Stream to print the string to");
617
618 return DumpUTFBufferToStream<UTF8>(nullptr, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
619}
620
621template <>
622bool
Shawn Bestfd137432014-11-04 22:43:34 +0000623ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000624{
625 // treat ASCII the same as UTF8
626 // FIXME: can we optimize ASCII some more?
627 return ReadBufferAndDumpToStream<StringElementType::UTF8>(options);
628}
629
630template <>
631bool
Shawn Bestfd137432014-11-04 22:43:34 +0000632ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000633{
634 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000635
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000636 return DumpUTFBufferToStream(ConvertUTF16toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
637}
638
639template <>
640bool
Shawn Bestfd137432014-11-04 22:43:34 +0000641ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000642{
643 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000644
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000645 return DumpUTFBufferToStream(ConvertUTF32toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables());
646}
Shawn Bestfd137432014-11-04 22:43:34 +0000647
648} // namespace formatters
649
650} // namespace lldb_private