UNPKG

@adguard/agtree

Version:
132 lines (129 loc) 6.69 kB
/* * AGTree v3.2.1 (build date: Wed, 28 May 2025 13:36:39 GMT) * (c) 2025 Adguard Software Ltd. * Released under the MIT license * https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme */ import { AdblockSyntax } from '../../utils/adblockers.js'; import { DomainListDeserializer } from '../misc/domain-list-deserializer.js'; import { NULL } from '../../utils/constants.js'; import { RuleCategory, CosmeticRuleType } from '../../nodes/index.js'; import { AbpSnippetInjectionBodyDeserializer } from './scriptlet-body/abp-snippet-injection-body-deserializer.js'; import { UboScriptletInjectionBodyDeserializer } from './scriptlet-body/ubo-scriptlet-injection-body-deserializer.js'; import { AdgScriptletInjectionBodyDeserializer } from './scriptlet-body/adg-scriptlet-injection-body-deserializer.js'; import { ValueDeserializer } from '../misc/value-deserializer.js'; import { isUndefined } from '../../utils/type-guards.js'; import { BaseDeserializer } from '../base-deserializer.js'; import { ElementHidingBodyDeserializer } from './element-hiding-body-deserializer.js'; import { CssInjectionBodyDeserializer } from './css-injection-body-deserializer.js'; import { ModifierListDeserializer } from '../misc/modifier-list-deserializer.js'; import { CosmeticRuleMarshallingMap, COSMETIC_RULE_SEPARATOR_SERIALIZATION_MAP } from '../../marshalling-utils/cosmetic/cosmetic-rule-common.js'; import { BinaryTypeMarshallingMap } from '../../marshalling-utils/misc/binary-type-common.js'; import { getSyntaxDeserializationMap } from '../syntax-deserialization-map.js'; /* eslint-disable no-param-reassign */ /** * Value map for binary deserialization. This helps to reduce the size of the serialized data, * as it allows us to use a single byte to represent frequently used values. */ let cosmeticRuleSeparatorDeserializationMap; const getCosmeticRuleSeparatorDeserializationMap = () => { if (!cosmeticRuleSeparatorDeserializationMap) { cosmeticRuleSeparatorDeserializationMap = new Map(Array.from(COSMETIC_RULE_SEPARATOR_SERIALIZATION_MAP).map(([key, value]) => [value, key])); } return cosmeticRuleSeparatorDeserializationMap; }; /** * Value map for binary deserialization. This helps to reduce the size of the serialized data, * as it allows us to use a single byte to represent frequently used values. */ const COSMETIC_RULE_TYPE_DESERIALIZATION_MAP = new Map([ [BinaryTypeMarshallingMap.ElementHidingRule, CosmeticRuleType.ElementHidingRule], [BinaryTypeMarshallingMap.CssInjectionRule, CosmeticRuleType.CssInjectionRule], [BinaryTypeMarshallingMap.ScriptletInjectionRule, CosmeticRuleType.ScriptletInjectionRule], [BinaryTypeMarshallingMap.JsInjectionRule, CosmeticRuleType.JsInjectionRule], [BinaryTypeMarshallingMap.HtmlFilteringRule, CosmeticRuleType.HtmlFilteringRule], ]); /** * Deserializer for cosmetic rules. * Converts binary data into structured cosmetic rule nodes, supporting various types * like element hiding, CSS injection, scriptlet injection, JavaScript injection, and HTML filtering. * Handles rule type, syntax, exceptions, separators, modifiers, and domain lists. */ class CosmeticRuleDeserializer extends BaseDeserializer { /** * Deserializes a cosmetic rule node from binary format. * * @param buffer ByteBuffer for reading binary data. * @param node Destination node. */ static deserialize(buffer, node) { const type = COSMETIC_RULE_TYPE_DESERIALIZATION_MAP.get(buffer.readUint8()); if (isUndefined(type)) { throw new Error(`Unknown rule type: ${type}`); } node.type = type; node.category = RuleCategory.Cosmetic; const syntax = getSyntaxDeserializationMap().get(buffer.readUint8()) ?? AdblockSyntax.Common; node.syntax = syntax; node.modifiers = undefined; switch (type) { case CosmeticRuleType.ElementHidingRule: ElementHidingBodyDeserializer.deserializeElementHidingBody(buffer, node.body = {}); break; case CosmeticRuleType.CssInjectionRule: CssInjectionBodyDeserializer.deserialize(buffer, node.body = {}); break; case CosmeticRuleType.JsInjectionRule: ValueDeserializer.deserialize(buffer, node.body = {}); break; case CosmeticRuleType.HtmlFilteringRule: ValueDeserializer.deserialize(buffer, node.body = {}); break; case CosmeticRuleType.ScriptletInjectionRule: switch (syntax) { case AdblockSyntax.Adg: AdgScriptletInjectionBodyDeserializer.deserialize(buffer, node.body = {}); break; case AdblockSyntax.Abp: AbpSnippetInjectionBodyDeserializer.deserialize(buffer, node.body = {}); break; case AdblockSyntax.Ubo: UboScriptletInjectionBodyDeserializer.deserialize(buffer, node.body = {}); break; default: throw new Error('Scriptlet rule should have an explicit syntax'); } break; default: throw new Error('Unknown cosmetic rule type'); } let prop = buffer.readUint8(); while (prop !== NULL) { switch (prop) { case CosmeticRuleMarshallingMap.Exception: node.exception = buffer.readUint8() === 1; break; case CosmeticRuleMarshallingMap.Separator: ValueDeserializer.deserialize(buffer, node.separator = {}, getCosmeticRuleSeparatorDeserializationMap()); break; case CosmeticRuleMarshallingMap.Modifiers: node.modifiers = {}; ModifierListDeserializer.deserialize(buffer, node.modifiers); break; case CosmeticRuleMarshallingMap.Domains: DomainListDeserializer.deserialize(buffer, node.domains = {}); break; case CosmeticRuleMarshallingMap.Start: node.start = buffer.readUint32(); break; case CosmeticRuleMarshallingMap.End: node.end = buffer.readUint32(); break; default: throw new Error(`Unknown property: ${prop}`); } prop = buffer.readUint8(); } } } export { CosmeticRuleDeserializer };