1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {RawDataUtils} from 'parsers/raw_data_utils'; 18import { 19 TamperedMessageType, 20 TamperedProtoField, 21} from 'parsers/tampered_message_type'; 22import * as protobuf from 'protobufjs'; 23import { 24 BUFFER_FORMATTER, 25 COLOR_FORMATTER, 26 DEFAULT_PROPERTY_FORMATTER, 27 EnumFormatter, 28 MATRIX_FORMATTER, 29 POSITION_FORMATTER, 30 PropertyFormatter, 31 RECT_FORMATTER, 32 REGION_FORMATTER, 33 SIZE_FORMATTER, 34 TRANSFORM_FORMATTER, 35} from 'trace/tree_node/formatters'; 36import {Operation} from 'trace/tree_node/operations/operation'; 37import {PropertyTreeNode} from 'trace/tree_node/property_tree_node'; 38 39export class SetFormatters implements Operation<PropertyTreeNode> { 40 private static readonly TransformRegExp = new RegExp('transform', 'i'); 41 42 constructor( 43 private readonly rootField?: TamperedProtoField, 44 private readonly customFormatters?: Map<string, PropertyFormatter>, 45 ) {} 46 47 apply(value: PropertyTreeNode, parentField = this.rootField): void { 48 let field: TamperedProtoField | undefined; 49 let enumType: protobuf.Enum | undefined; 50 51 if (parentField) { 52 const protoType: TamperedMessageType | undefined = 53 parentField.tamperedMessageType; 54 55 field = parentField; 56 if (protoType && field.name !== value.name) { 57 field = protoType.fields[value.name] ?? parentField; 58 } 59 60 enumType = field.tamperedEnumType; 61 } 62 63 const formatter = this.getFormatter(value, enumType?.valuesById); 64 65 if (formatter) value.setFormatter(formatter); 66 67 value.getAllChildren().forEach((value) => { 68 this.apply(value, field); 69 }); 70 } 71 72 private getFormatter( 73 node: PropertyTreeNode, 74 valuesById: {[key: number]: string} | undefined, 75 ): PropertyFormatter | undefined { 76 if (this.customFormatters?.get(node.name)) { 77 return this.customFormatters.get(node.name); 78 } 79 80 if (valuesById) return new EnumFormatter(valuesById); 81 82 if (RawDataUtils.isColor(node)) return COLOR_FORMATTER; 83 if (RawDataUtils.isRect(node)) return RECT_FORMATTER; 84 if (RawDataUtils.isBuffer(node)) return BUFFER_FORMATTER; 85 if (RawDataUtils.isSize(node)) return SIZE_FORMATTER; 86 if (RawDataUtils.isRegion(node)) return REGION_FORMATTER; 87 if (RawDataUtils.isPosition(node)) return POSITION_FORMATTER; 88 if ( 89 SetFormatters.TransformRegExp.test(node.name) && 90 node.getChildByName('type') 91 ) { 92 return TRANSFORM_FORMATTER; 93 } 94 if (RawDataUtils.isMatrix(node)) return MATRIX_FORMATTER; 95 96 if (node.getAllChildren().length > 0) return undefined; 97 98 return DEFAULT_PROPERTY_FORMATTER; 99 } 100} 101