180814287SRaphael Isemann //===-- NSString.cpp ------------------------------------------------------===//
27de855c6SEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67de855c6SEnrico Granata //
77de855c6SEnrico Granata //===----------------------------------------------------------------------===//
87de855c6SEnrico Granata
97de855c6SEnrico Granata #include "NSString.h"
107de855c6SEnrico Granata
117de855c6SEnrico Granata #include "lldb/Core/ValueObject.h"
127de855c6SEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
137de855c6SEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
147de855c6SEnrico Granata #include "lldb/DataFormatters/StringPrinter.h"
15675f49bbSEnrico Granata #include "lldb/Target/Language.h"
167de855c6SEnrico Granata #include "lldb/Target/Target.h"
17*9d9f3e0eSDave Lee #include "lldb/Utility/ConstString.h"
18666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
1901c3243fSZachary Turner #include "lldb/Utility/Endian.h"
2097206d57SZachary Turner #include "lldb/Utility/Status.h"
21bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
227de855c6SEnrico Granata
237de855c6SEnrico Granata using namespace lldb;
247de855c6SEnrico Granata using namespace lldb_private;
257de855c6SEnrico Granata using namespace lldb_private::formatters;
267de855c6SEnrico Granata
277de855c6SEnrico Granata std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
GetAdditionalSummaries()28b9c1b51eSKate Stone NSString_Additionals::GetAdditionalSummaries() {
297de855c6SEnrico Granata static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
307de855c6SEnrico Granata return g_map;
317de855c6SEnrico Granata }
327de855c6SEnrico Granata
NSStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & summary_options)33b9c1b51eSKate Stone bool lldb_private::formatters::NSStringSummaryProvider(
34b9c1b51eSKate Stone ValueObject &valobj, Stream &stream,
35b9c1b51eSKate Stone const TypeSummaryOptions &summary_options) {
36675f49bbSEnrico Granata static ConstString g_TypeHint("NSString");
37675f49bbSEnrico Granata
387de855c6SEnrico Granata ProcessSP process_sp = valobj.GetProcessSP();
397de855c6SEnrico Granata if (!process_sp)
407de855c6SEnrico Granata return false;
417de855c6SEnrico Granata
42e823bbe8SAlex Langford ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
437de855c6SEnrico Granata
447de855c6SEnrico Granata if (!runtime)
457de855c6SEnrico Granata return false;
467de855c6SEnrico Granata
47b9c1b51eSKate Stone ObjCLanguageRuntime::ClassDescriptorSP descriptor(
48b9c1b51eSKate Stone runtime->GetClassDescriptor(valobj));
497de855c6SEnrico Granata
507de855c6SEnrico Granata if (!descriptor.get() || !descriptor->IsValid())
517de855c6SEnrico Granata return false;
527de855c6SEnrico Granata
537de855c6SEnrico Granata uint32_t ptr_size = process_sp->GetAddressByteSize();
547de855c6SEnrico Granata
557de855c6SEnrico Granata lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
567de855c6SEnrico Granata
577de855c6SEnrico Granata if (!valobj_addr)
587de855c6SEnrico Granata return false;
597de855c6SEnrico Granata
607de855c6SEnrico Granata ConstString class_name_cs = descriptor->GetClassName();
616bac09afSRaphael Isemann llvm::StringRef class_name = class_name_cs.GetStringRef();
627de855c6SEnrico Granata
636bac09afSRaphael Isemann if (class_name.empty())
647de855c6SEnrico Granata return false;
657de855c6SEnrico Granata
666bac09afSRaphael Isemann bool is_tagged_ptr = class_name == "NSTaggedPointerString" &&
67b9c1b51eSKate Stone descriptor->GetTaggedPointerInfo();
687de855c6SEnrico Granata // for a tagged pointer, the descriptor has everything we need
697de855c6SEnrico Granata if (is_tagged_ptr)
70b9c1b51eSKate Stone return NSTaggedString_SummaryProvider(valobj, descriptor, stream,
71b9c1b51eSKate Stone summary_options);
727de855c6SEnrico Granata
737de855c6SEnrico Granata auto &additionals_map(NSString_Additionals::GetAdditionalSummaries());
747de855c6SEnrico Granata auto iter = additionals_map.find(class_name_cs), end = additionals_map.end();
757de855c6SEnrico Granata if (iter != end)
767de855c6SEnrico Granata return iter->second(valobj, stream, summary_options);
777de855c6SEnrico Granata
787de855c6SEnrico Granata // if not a tagged pointer that we know about, try the normal route
797de855c6SEnrico Granata uint64_t info_bits_location = valobj_addr + ptr_size;
807de855c6SEnrico Granata if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
817de855c6SEnrico Granata info_bits_location += 3;
827de855c6SEnrico Granata
8397206d57SZachary Turner Status error;
847de855c6SEnrico Granata
85b9c1b51eSKate Stone uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(
86b9c1b51eSKate Stone info_bits_location, 1, 0, error);
877de855c6SEnrico Granata if (error.Fail())
887de855c6SEnrico Granata return false;
897de855c6SEnrico Granata
907de855c6SEnrico Granata bool is_mutable = (info_bits & 1) == 1;
917de855c6SEnrico Granata bool is_inline = (info_bits & 0x60) == 0;
927de855c6SEnrico Granata bool has_explicit_length = (info_bits & (1 | 4)) != 4;
937de855c6SEnrico Granata bool is_unicode = (info_bits & 0x10) == 0x10;
946bac09afSRaphael Isemann bool is_path_store = class_name == "NSPathStore2";
957de855c6SEnrico Granata bool has_null = (info_bits & 8) == 8;
967de855c6SEnrico Granata
977de855c6SEnrico Granata size_t explicit_length = 0;
98b9c1b51eSKate Stone if (!has_null && has_explicit_length && !is_path_store) {
997de855c6SEnrico Granata lldb::addr_t explicit_length_offset = 2 * ptr_size;
1007de855c6SEnrico Granata if (is_mutable && !is_inline)
101b9c1b51eSKate Stone explicit_length_offset =
102b9c1b51eSKate Stone explicit_length_offset + ptr_size; // notInlineMutable.length;
1037de855c6SEnrico Granata else if (is_inline)
1047de855c6SEnrico Granata explicit_length = explicit_length + 0; // inline1.length;
1057de855c6SEnrico Granata else if (!is_inline && !is_mutable)
106b9c1b51eSKate Stone explicit_length_offset =
107b9c1b51eSKate Stone explicit_length_offset + ptr_size; // notInlineImmutable1.length;
1087de855c6SEnrico Granata else
1097de855c6SEnrico Granata explicit_length_offset = 0;
1107de855c6SEnrico Granata
111b9c1b51eSKate Stone if (explicit_length_offset) {
1127de855c6SEnrico Granata explicit_length_offset = valobj_addr + explicit_length_offset;
113b9c1b51eSKate Stone explicit_length = process_sp->ReadUnsignedIntegerFromMemory(
114b9c1b51eSKate Stone explicit_length_offset, 4, 0, error);
1157de855c6SEnrico Granata }
1167de855c6SEnrico Granata }
1177de855c6SEnrico Granata
1186bac09afSRaphael Isemann const llvm::StringSet<> supported_string_classes = {
1196bac09afSRaphael Isemann "NSString", "CFMutableStringRef",
1206bac09afSRaphael Isemann "CFStringRef", "__NSCFConstantString",
1216bac09afSRaphael Isemann "__NSCFString", "NSCFConstantString",
1226bac09afSRaphael Isemann "NSCFString", "NSPathStore2"};
1236bac09afSRaphael Isemann if (supported_string_classes.count(class_name) == 0) {
1247de855c6SEnrico Granata // not one of us - but tell me class name
1256bac09afSRaphael Isemann stream.Printf("class name = %s", class_name_cs.GetCString());
1267de855c6SEnrico Granata return true;
1277de855c6SEnrico Granata }
1287de855c6SEnrico Granata
129675f49bbSEnrico Granata std::string prefix, suffix;
130b9c1b51eSKate Stone if (Language *language =
131b9c1b51eSKate Stone Language::FindPlugin(summary_options.GetLanguage())) {
132b9c1b51eSKate Stone if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
133b9c1b51eSKate Stone suffix)) {
134675f49bbSEnrico Granata prefix.clear();
135675f49bbSEnrico Granata suffix.clear();
136675f49bbSEnrico Granata }
137675f49bbSEnrico Granata }
138675f49bbSEnrico Granata
139675f49bbSEnrico Granata StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
140675f49bbSEnrico Granata options.SetPrefixToken(prefix);
141675f49bbSEnrico Granata options.SetSuffixToken(suffix);
142675f49bbSEnrico Granata
143b9c1b51eSKate Stone if (is_mutable) {
1447de855c6SEnrico Granata uint64_t location = 2 * ptr_size + valobj_addr;
1457de855c6SEnrico Granata location = process_sp->ReadPointerFromMemory(location, error);
1467de855c6SEnrico Granata if (error.Fail())
1477de855c6SEnrico Granata return false;
148b9c1b51eSKate Stone if (has_explicit_length && is_unicode) {
1497de855c6SEnrico Granata options.SetLocation(location);
1504c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
1517de855c6SEnrico Granata options.SetStream(&stream);
1527de855c6SEnrico Granata options.SetQuote('"');
1537de855c6SEnrico Granata options.SetSourceSize(explicit_length);
1547b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
1557de855c6SEnrico Granata options.SetNeedsZeroTermination(false);
156b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
157b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
1587de855c6SEnrico Granata options.SetBinaryZeroIsTerminator(false);
159b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
160b9c1b51eSKate Stone StringPrinter::StringElementType::UTF16>(options);
161b9c1b51eSKate Stone } else {
1627de855c6SEnrico Granata options.SetLocation(location + 1);
1634c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
1647de855c6SEnrico Granata options.SetStream(&stream);
1657de855c6SEnrico Granata options.SetSourceSize(explicit_length);
1667b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
1677de855c6SEnrico Granata options.SetNeedsZeroTermination(false);
168b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
169b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
1707de855c6SEnrico Granata options.SetBinaryZeroIsTerminator(false);
171b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
172b9c1b51eSKate Stone StringPrinter::StringElementType::ASCII>(options);
1737de855c6SEnrico Granata }
174b9c1b51eSKate Stone } else if (is_inline && has_explicit_length && !is_unicode &&
175b9c1b51eSKate Stone !is_path_store && !is_mutable) {
1767de855c6SEnrico Granata uint64_t location = 3 * ptr_size + valobj_addr;
1777de855c6SEnrico Granata
1787de855c6SEnrico Granata options.SetLocation(location);
1794c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
1807de855c6SEnrico Granata options.SetStream(&stream);
1817de855c6SEnrico Granata options.SetQuote('"');
1827de855c6SEnrico Granata options.SetSourceSize(explicit_length);
1837b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
184b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
185b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
186b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
187b9c1b51eSKate Stone StringPrinter::StringElementType::ASCII>(options);
188b9c1b51eSKate Stone } else if (is_unicode) {
1897de855c6SEnrico Granata uint64_t location = valobj_addr + 2 * ptr_size;
190b9c1b51eSKate Stone if (is_inline) {
191b9c1b51eSKate Stone if (!has_explicit_length) {
192c8af52dfSEnrico Granata return false;
193b9c1b51eSKate Stone } else
1947de855c6SEnrico Granata location += ptr_size;
195b9c1b51eSKate Stone } else {
1967de855c6SEnrico Granata location = process_sp->ReadPointerFromMemory(location, error);
1977de855c6SEnrico Granata if (error.Fail())
1987de855c6SEnrico Granata return false;
1997de855c6SEnrico Granata }
2007de855c6SEnrico Granata options.SetLocation(location);
2014c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
2027de855c6SEnrico Granata options.SetStream(&stream);
2037de855c6SEnrico Granata options.SetQuote('"');
2047de855c6SEnrico Granata options.SetSourceSize(explicit_length);
2057b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
206a6682a41SJonas Devlieghere options.SetNeedsZeroTermination(!has_explicit_length);
207b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
208b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
209a6682a41SJonas Devlieghere options.SetBinaryZeroIsTerminator(!has_explicit_length);
210b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
211b9c1b51eSKate Stone StringPrinter::StringElementType::UTF16>(options);
212b9c1b51eSKate Stone } else if (is_path_store) {
213*9d9f3e0eSDave Lee // _lengthAndRefCount is the first ivar of NSPathStore2 (after the isa).
214*9d9f3e0eSDave Lee uint64_t length_ivar_offset = 1 * ptr_size;
215*9d9f3e0eSDave Lee CompilerType length_type = valobj.GetCompilerType().GetBasicTypeFromAST(
216*9d9f3e0eSDave Lee lldb::eBasicTypeUnsignedInt);
217*9d9f3e0eSDave Lee ValueObjectSP length_valobj_sp =
218*9d9f3e0eSDave Lee valobj.GetSyntheticChildAtOffset(length_ivar_offset, length_type, true,
219*9d9f3e0eSDave Lee ConstString("_lengthAndRefCount"));
220*9d9f3e0eSDave Lee if (!length_valobj_sp)
221*9d9f3e0eSDave Lee return false;
222*9d9f3e0eSDave Lee // Get the length out of _lengthAndRefCount.
223*9d9f3e0eSDave Lee explicit_length = length_valobj_sp->GetValueAsUnsigned(0) >> 20;
2247de855c6SEnrico Granata lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
2257de855c6SEnrico Granata
2267de855c6SEnrico Granata options.SetLocation(location);
2274c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
2287de855c6SEnrico Granata options.SetStream(&stream);
2297de855c6SEnrico Granata options.SetQuote('"');
2307de855c6SEnrico Granata options.SetSourceSize(explicit_length);
2317b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
232a6682a41SJonas Devlieghere options.SetNeedsZeroTermination(!has_explicit_length);
233b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
234b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
235a6682a41SJonas Devlieghere options.SetBinaryZeroIsTerminator(!has_explicit_length);
236b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
237b9c1b51eSKate Stone StringPrinter::StringElementType::UTF16>(options);
238b9c1b51eSKate Stone } else if (is_inline) {
2397de855c6SEnrico Granata uint64_t location = valobj_addr + 2 * ptr_size;
240b9c1b51eSKate Stone if (!has_explicit_length) {
241b9c1b51eSKate Stone // in this kind of string, the byte before the string content is a length
24205097246SAdrian Prantl // byte so let's try and use it to handle the embedded NUL case
24397206d57SZachary Turner Status error;
244b9c1b51eSKate Stone explicit_length =
245b9c1b51eSKate Stone process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
246a6682a41SJonas Devlieghere has_explicit_length = !(error.Fail() || explicit_length == 0);
2477de855c6SEnrico Granata location++;
2487de855c6SEnrico Granata }
2497de855c6SEnrico Granata options.SetLocation(location);
2504c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
2517de855c6SEnrico Granata options.SetStream(&stream);
2527de855c6SEnrico Granata options.SetSourceSize(explicit_length);
2537b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
2547de855c6SEnrico Granata options.SetNeedsZeroTermination(!has_explicit_length);
255b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
256b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
2577de855c6SEnrico Granata options.SetBinaryZeroIsTerminator(!has_explicit_length);
2587de855c6SEnrico Granata if (has_explicit_length)
259b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
260b9c1b51eSKate Stone StringPrinter::StringElementType::UTF8>(options);
2617de855c6SEnrico Granata else
262b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
263b9c1b51eSKate Stone StringPrinter::StringElementType::ASCII>(options);
264b9c1b51eSKate Stone } else {
2657de855c6SEnrico Granata uint64_t location = valobj_addr + 2 * ptr_size;
2667de855c6SEnrico Granata location = process_sp->ReadPointerFromMemory(location, error);
2677de855c6SEnrico Granata if (error.Fail())
2687de855c6SEnrico Granata return false;
2697de855c6SEnrico Granata if (has_explicit_length && !has_null)
270b9c1b51eSKate Stone explicit_length++; // account for the fact that there is no NULL and we
271b9c1b51eSKate Stone // need to have one added
2727de855c6SEnrico Granata options.SetLocation(location);
2734c56f734SPavel Labath options.SetTargetSP(valobj.GetTargetSP());
2747de855c6SEnrico Granata options.SetStream(&stream);
2757de855c6SEnrico Granata options.SetSourceSize(explicit_length);
2767b244258SRaphael Isemann options.SetHasSourceSize(has_explicit_length);
277b9c1b51eSKate Stone options.SetIgnoreMaxLength(summary_options.GetCapping() ==
278b9c1b51eSKate Stone TypeSummaryCapping::eTypeSummaryUncapped);
279b9c1b51eSKate Stone return StringPrinter::ReadStringAndDumpToStream<
280b9c1b51eSKate Stone StringPrinter::StringElementType::ASCII>(options);
2817de855c6SEnrico Granata }
2827de855c6SEnrico Granata }
2837de855c6SEnrico Granata
NSAttributedStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)284b9c1b51eSKate Stone bool lldb_private::formatters::NSAttributedStringSummaryProvider(
285b9c1b51eSKate Stone ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
2867de855c6SEnrico Granata TargetSP target_sp(valobj.GetTargetSP());
2877de855c6SEnrico Granata if (!target_sp)
2887de855c6SEnrico Granata return false;
2897de855c6SEnrico Granata uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
2907de855c6SEnrico Granata uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
2917de855c6SEnrico Granata if (!pointer_value)
2927de855c6SEnrico Granata return false;
2937de855c6SEnrico Granata pointer_value += addr_size;
2947de855c6SEnrico Granata CompilerType type(valobj.GetCompilerType());
2957de855c6SEnrico Granata ExecutionContext exe_ctx(target_sp, false);
296b9c1b51eSKate Stone ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress(
297b9c1b51eSKate Stone "string_ptr", pointer_value, exe_ctx, type));
2987de855c6SEnrico Granata if (!child_ptr_sp)
2997de855c6SEnrico Granata return false;
3007de855c6SEnrico Granata DataExtractor data;
30197206d57SZachary Turner Status error;
3027de855c6SEnrico Granata child_ptr_sp->GetData(data, error);
3037de855c6SEnrico Granata if (error.Fail())
3047de855c6SEnrico Granata return false;
305b9c1b51eSKate Stone ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData(
306b9c1b51eSKate Stone "string_data", data, exe_ctx, type));
3077de855c6SEnrico Granata child_sp->GetValueAsUnsigned(0);
3087de855c6SEnrico Granata if (child_sp)
3097de855c6SEnrico Granata return NSStringSummaryProvider(*child_sp, stream, options);
3107de855c6SEnrico Granata return false;
3117de855c6SEnrico Granata }
3127de855c6SEnrico Granata
NSMutableAttributedStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)313b9c1b51eSKate Stone bool lldb_private::formatters::NSMutableAttributedStringSummaryProvider(
314b9c1b51eSKate Stone ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
3157de855c6SEnrico Granata return NSAttributedStringSummaryProvider(valobj, stream, options);
3167de855c6SEnrico Granata }
3177de855c6SEnrico Granata
NSTaggedString_SummaryProvider(ValueObject & valobj,ObjCLanguageRuntime::ClassDescriptorSP descriptor,Stream & stream,const TypeSummaryOptions & summary_options)318b9c1b51eSKate Stone bool lldb_private::formatters::NSTaggedString_SummaryProvider(
319b9c1b51eSKate Stone ValueObject &valobj, ObjCLanguageRuntime::ClassDescriptorSP descriptor,
320b9c1b51eSKate Stone Stream &stream, const TypeSummaryOptions &summary_options) {
321675f49bbSEnrico Granata static ConstString g_TypeHint("NSString");
322675f49bbSEnrico Granata
3237de855c6SEnrico Granata if (!descriptor)
3247de855c6SEnrico Granata return false;
3257de855c6SEnrico Granata uint64_t len_bits = 0, data_bits = 0;
3267de855c6SEnrico Granata if (!descriptor->GetTaggedPointerInfo(&len_bits, &data_bits, nullptr))
3277de855c6SEnrico Granata return false;
3287de855c6SEnrico Granata
3297de855c6SEnrico Granata static const int g_MaxNonBitmaskedLen = 7; // TAGGED_STRING_UNPACKED_MAXLEN
3307de855c6SEnrico Granata static const int g_SixbitMaxLen = 9;
3317de855c6SEnrico Granata static const int g_fiveBitMaxLen = 11;
3327de855c6SEnrico Granata
333b9c1b51eSKate Stone static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013"
334b9c1b51eSKate Stone "bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";
3357de855c6SEnrico Granata
3367de855c6SEnrico Granata if (len_bits > g_fiveBitMaxLen)
3377de855c6SEnrico Granata return false;
3387de855c6SEnrico Granata
339675f49bbSEnrico Granata std::string prefix, suffix;
340b9c1b51eSKate Stone if (Language *language =
341b9c1b51eSKate Stone Language::FindPlugin(summary_options.GetLanguage())) {
342b9c1b51eSKate Stone if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
343b9c1b51eSKate Stone suffix)) {
344675f49bbSEnrico Granata prefix.clear();
345675f49bbSEnrico Granata suffix.clear();
346675f49bbSEnrico Granata }
347675f49bbSEnrico Granata }
348675f49bbSEnrico Granata
349b9c1b51eSKate Stone // this is a fairly ugly trick - pretend that the numeric value is actually a
35005097246SAdrian Prantl // char* this works under a few assumptions: little endian architecture
3517de855c6SEnrico Granata // sizeof(uint64_t) > g_MaxNonBitmaskedLen
352b9c1b51eSKate Stone if (len_bits <= g_MaxNonBitmaskedLen) {
353675f49bbSEnrico Granata stream.Printf("%s", prefix.c_str());
354675f49bbSEnrico Granata stream.Printf("\"%s\"", (const char *)&data_bits);
355675f49bbSEnrico Granata stream.Printf("%s", suffix.c_str());
3567de855c6SEnrico Granata return true;
3577de855c6SEnrico Granata }
3587de855c6SEnrico Granata
3597de855c6SEnrico Granata // if the data is bitmasked, we need to actually process the bytes
3607de855c6SEnrico Granata uint8_t bitmask = 0;
3617de855c6SEnrico Granata uint8_t shift_offset = 0;
3627de855c6SEnrico Granata
363b9c1b51eSKate Stone if (len_bits <= g_SixbitMaxLen) {
3647de855c6SEnrico Granata bitmask = 0x03f;
3657de855c6SEnrico Granata shift_offset = 6;
366b9c1b51eSKate Stone } else {
3677de855c6SEnrico Granata bitmask = 0x01f;
3687de855c6SEnrico Granata shift_offset = 5;
3697de855c6SEnrico Granata }
3707de855c6SEnrico Granata
3717de855c6SEnrico Granata std::vector<uint8_t> bytes;
3727de855c6SEnrico Granata bytes.resize(len_bits);
373b9c1b51eSKate Stone for (; len_bits > 0; data_bits >>= shift_offset, --len_bits) {
3747de855c6SEnrico Granata uint8_t packed = data_bits & bitmask;
3757de855c6SEnrico Granata bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
3767de855c6SEnrico Granata }
3777de855c6SEnrico Granata
378675f49bbSEnrico Granata stream.Printf("%s", prefix.c_str());
379675f49bbSEnrico Granata stream.Printf("\"%s\"", &bytes[0]);
380675f49bbSEnrico Granata stream.Printf("%s", suffix.c_str());
3817de855c6SEnrico Granata return true;
3827de855c6SEnrico Granata }
383