blob: 15cd8a97cb37e0c5c8511e4bb454376e47ba7fba [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {assertDefined} from 'common/assert_utils';
import {
TamperedMessageType,
TamperedProtoField,
} from 'parsers/tampered_message_type';
import {AddOperation} from 'trace/tree_node/operations/add_operation';
import {PropertyTreeNode} from 'trace/tree_node/property_tree_node';
import {DEFAULT_PROPERTY_TREE_NODE_FACTORY} from 'trace/tree_node/property_tree_node_factory';
export class AddDefaults extends AddOperation<PropertyTreeNode> {
private readonly protoType: TamperedMessageType;
constructor(
protoField: TamperedProtoField,
private readonly propertyAllowlist?: string[],
private readonly propertyDenylist?: string[],
) {
super();
this.protoType = assertDefined(protoField.tamperedMessageType);
}
override makeProperties(value: PropertyTreeNode): PropertyTreeNode[] {
const defaultPropertyNodes: PropertyTreeNode[] = [];
for (const fieldName in this.protoType.fields) {
if (
this.propertyAllowlist &&
!this.propertyAllowlist.includes(fieldName)
) {
continue;
}
if (this.propertyDenylist && this.propertyDenylist.includes(fieldName)) {
continue;
}
if (
!Object.prototype.hasOwnProperty.call(this.protoType.fields, fieldName)
) {
continue;
}
const field = this.protoType.fields[fieldName];
let existingNode = value.getChildByName(fieldName);
let defaultValue: any = field.repeated ? [] : field.defaultValue;
if (!field.repeated && defaultValue === null) {
switch (field.type) {
case 'double':
defaultValue = 0;
break;
case 'float':
defaultValue = 0;
break;
case 'int32':
defaultValue = 0;
break;
case 'uint32':
defaultValue = 0;
break;
case 'sint32':
defaultValue = 0;
break;
case 'fixed32':
defaultValue = 0;
break;
case 'sfixed32':
defaultValue = 0;
break;
case 'int64':
defaultValue = BigInt(0);
break;
case 'uint64':
defaultValue = BigInt(0);
break;
case 'sint64':
defaultValue = BigInt(0);
break;
case 'fixed64':
defaultValue = BigInt(0);
break;
case 'sfixed64':
defaultValue = BigInt(0);
break;
case 'bool':
defaultValue = Boolean(defaultValue);
break;
default:
//do nothing
}
}
if (
!existingNode ||
existingNode.getValue() === defaultValue ||
(existingNode.getValue() === undefined &&
existingNode.getAllChildren().length === 0)
) {
existingNode = DEFAULT_PROPERTY_TREE_NODE_FACTORY.makeDefaultProperty(
value.id,
fieldName,
defaultValue,
);
defaultPropertyNodes.push(existingNode);
continue;
}
if (field.tamperedMessageType) {
const operation = new AddDefaults(field);
if (field.repeated) {
existingNode
.getAllChildren()
.forEach((child) => operation.apply(child));
} else {
operation.apply(existingNode);
}
}
}
return defaultPropertyNodes;
}
}