1ffe3c632Sopenharmony_ci#region Copyright notice and license 2ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format 3ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc. All rights reserved. 4ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/ 5ffe3c632Sopenharmony_ci// 6ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without 7ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are 8ffe3c632Sopenharmony_ci// met: 9ffe3c632Sopenharmony_ci// 10ffe3c632Sopenharmony_ci// * Redistributions of source code must retain the above copyright 11ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer. 12ffe3c632Sopenharmony_ci// * Redistributions in binary form must reproduce the above 13ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer 14ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the 15ffe3c632Sopenharmony_ci// distribution. 16ffe3c632Sopenharmony_ci// * Neither the name of Google Inc. nor the names of its 17ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from 18ffe3c632Sopenharmony_ci// this software without specific prior written permission. 19ffe3c632Sopenharmony_ci// 20ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31ffe3c632Sopenharmony_ci#endregion 32ffe3c632Sopenharmony_ci 33ffe3c632Sopenharmony_ciusing System; 34ffe3c632Sopenharmony_ciusing System.Buffers; 35ffe3c632Sopenharmony_ciusing System.Buffers.Binary; 36ffe3c632Sopenharmony_ciusing System.Collections.Generic; 37ffe3c632Sopenharmony_ciusing System.IO; 38ffe3c632Sopenharmony_ciusing System.Runtime.CompilerServices; 39ffe3c632Sopenharmony_ciusing System.Runtime.InteropServices; 40ffe3c632Sopenharmony_ciusing System.Security; 41ffe3c632Sopenharmony_ciusing System.Text; 42ffe3c632Sopenharmony_ciusing Google.Protobuf.Collections; 43ffe3c632Sopenharmony_ci 44ffe3c632Sopenharmony_cinamespace Google.Protobuf 45ffe3c632Sopenharmony_ci{ 46ffe3c632Sopenharmony_ci /// <summary> 47ffe3c632Sopenharmony_ci /// An opaque struct that represents the current parsing state and is passed along 48ffe3c632Sopenharmony_ci /// as the parsing proceeds. 49ffe3c632Sopenharmony_ci /// All the public methods are intended to be invoked only by the generated code, 50ffe3c632Sopenharmony_ci /// users should never invoke them directly. 51ffe3c632Sopenharmony_ci /// </summary> 52ffe3c632Sopenharmony_ci [SecuritySafeCritical] 53ffe3c632Sopenharmony_ci public ref struct ParseContext 54ffe3c632Sopenharmony_ci { 55ffe3c632Sopenharmony_ci internal const int DefaultRecursionLimit = 100; 56ffe3c632Sopenharmony_ci internal const int DefaultSizeLimit = Int32.MaxValue; 57ffe3c632Sopenharmony_ci 58ffe3c632Sopenharmony_ci internal ReadOnlySpan<byte> buffer; 59ffe3c632Sopenharmony_ci internal ParserInternalState state; 60ffe3c632Sopenharmony_ci 61ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 62ffe3c632Sopenharmony_ci internal static void Initialize(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, out ParseContext ctx) 63ffe3c632Sopenharmony_ci { 64ffe3c632Sopenharmony_ci ctx.buffer = buffer; 65ffe3c632Sopenharmony_ci ctx.state = state; 66ffe3c632Sopenharmony_ci } 67ffe3c632Sopenharmony_ci 68ffe3c632Sopenharmony_ci /// <summary> 69ffe3c632Sopenharmony_ci /// Creates a ParseContext instance from CodedInputStream. 70ffe3c632Sopenharmony_ci /// WARNING: internally this copies the CodedInputStream's state, so after done with the ParseContext, 71ffe3c632Sopenharmony_ci /// the CodedInputStream's state needs to be updated. 72ffe3c632Sopenharmony_ci /// </summary> 73ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 74ffe3c632Sopenharmony_ci internal static void Initialize(CodedInputStream input, out ParseContext ctx) 75ffe3c632Sopenharmony_ci { 76ffe3c632Sopenharmony_ci ctx.buffer = new ReadOnlySpan<byte>(input.InternalBuffer); 77ffe3c632Sopenharmony_ci // ideally we would use a reference to the original state, but that doesn't seem possible 78ffe3c632Sopenharmony_ci // so we just copy the struct that holds the state. We will need to later store the state back 79ffe3c632Sopenharmony_ci // into CodedInputStream if we want to keep it usable. 80ffe3c632Sopenharmony_ci ctx.state = input.InternalState; 81ffe3c632Sopenharmony_ci } 82ffe3c632Sopenharmony_ci 83ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 84ffe3c632Sopenharmony_ci internal static void Initialize(ReadOnlySequence<byte> input, out ParseContext ctx) 85ffe3c632Sopenharmony_ci { 86ffe3c632Sopenharmony_ci Initialize(input, DefaultRecursionLimit, out ctx); 87ffe3c632Sopenharmony_ci } 88ffe3c632Sopenharmony_ci 89ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 90ffe3c632Sopenharmony_ci internal static void Initialize(ReadOnlySequence<byte> input, int recursionLimit, out ParseContext ctx) 91ffe3c632Sopenharmony_ci { 92ffe3c632Sopenharmony_ci ctx.buffer = default; 93ffe3c632Sopenharmony_ci ctx.state = default; 94ffe3c632Sopenharmony_ci ctx.state.lastTag = 0; 95ffe3c632Sopenharmony_ci ctx.state.recursionDepth = 0; 96ffe3c632Sopenharmony_ci ctx.state.sizeLimit = DefaultSizeLimit; 97ffe3c632Sopenharmony_ci ctx.state.recursionLimit = recursionLimit; 98ffe3c632Sopenharmony_ci ctx.state.currentLimit = int.MaxValue; 99ffe3c632Sopenharmony_ci SegmentedBufferHelper.Initialize(input, out ctx.state.segmentedBufferHelper, out ctx.buffer); 100ffe3c632Sopenharmony_ci ctx.state.bufferPos = 0; 101ffe3c632Sopenharmony_ci ctx.state.bufferSize = ctx.buffer.Length; 102ffe3c632Sopenharmony_ci 103ffe3c632Sopenharmony_ci ctx.state.DiscardUnknownFields = false; 104ffe3c632Sopenharmony_ci ctx.state.ExtensionRegistry = null; 105ffe3c632Sopenharmony_ci } 106ffe3c632Sopenharmony_ci 107ffe3c632Sopenharmony_ci /// <summary> 108ffe3c632Sopenharmony_ci /// Returns the last tag read, or 0 if no tags have been read or we've read beyond 109ffe3c632Sopenharmony_ci /// the end of the input. 110ffe3c632Sopenharmony_ci /// </summary> 111ffe3c632Sopenharmony_ci internal uint LastTag { get { return state.lastTag; } } 112ffe3c632Sopenharmony_ci 113ffe3c632Sopenharmony_ci /// <summary> 114ffe3c632Sopenharmony_ci /// Internal-only property; when set to true, unknown fields will be discarded while parsing. 115ffe3c632Sopenharmony_ci /// </summary> 116ffe3c632Sopenharmony_ci internal bool DiscardUnknownFields { 117ffe3c632Sopenharmony_ci get { return state.DiscardUnknownFields; } 118ffe3c632Sopenharmony_ci set { state.DiscardUnknownFields = value; } 119ffe3c632Sopenharmony_ci } 120ffe3c632Sopenharmony_ci 121ffe3c632Sopenharmony_ci /// <summary> 122ffe3c632Sopenharmony_ci /// Internal-only property; provides extension identifiers to compatible messages while parsing. 123ffe3c632Sopenharmony_ci /// </summary> 124ffe3c632Sopenharmony_ci internal ExtensionRegistry ExtensionRegistry 125ffe3c632Sopenharmony_ci { 126ffe3c632Sopenharmony_ci get { return state.ExtensionRegistry; } 127ffe3c632Sopenharmony_ci set { state.ExtensionRegistry = value; } 128ffe3c632Sopenharmony_ci } 129ffe3c632Sopenharmony_ci 130ffe3c632Sopenharmony_ci /// <summary> 131ffe3c632Sopenharmony_ci /// Reads a field tag, returning the tag of 0 for "end of input". 132ffe3c632Sopenharmony_ci /// </summary> 133ffe3c632Sopenharmony_ci /// <remarks> 134ffe3c632Sopenharmony_ci /// If this method returns 0, it doesn't necessarily mean the end of all 135ffe3c632Sopenharmony_ci /// the data in this CodedInputReader; it may be the end of the logical input 136ffe3c632Sopenharmony_ci /// for an embedded message, for example. 137ffe3c632Sopenharmony_ci /// </remarks> 138ffe3c632Sopenharmony_ci /// <returns>The next field tag, or 0 for end of input. (0 is never a valid tag.)</returns> 139ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 140ffe3c632Sopenharmony_ci public uint ReadTag() 141ffe3c632Sopenharmony_ci { 142ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseTag(ref buffer, ref state); 143ffe3c632Sopenharmony_ci } 144ffe3c632Sopenharmony_ci 145ffe3c632Sopenharmony_ci /// <summary> 146ffe3c632Sopenharmony_ci /// Reads a double field from the input. 147ffe3c632Sopenharmony_ci /// </summary> 148ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 149ffe3c632Sopenharmony_ci public double ReadDouble() 150ffe3c632Sopenharmony_ci { 151ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseDouble(ref buffer, ref state); 152ffe3c632Sopenharmony_ci } 153ffe3c632Sopenharmony_ci 154ffe3c632Sopenharmony_ci /// <summary> 155ffe3c632Sopenharmony_ci /// Reads a float field from the input. 156ffe3c632Sopenharmony_ci /// </summary> 157ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 158ffe3c632Sopenharmony_ci public float ReadFloat() 159ffe3c632Sopenharmony_ci { 160ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseFloat(ref buffer, ref state); 161ffe3c632Sopenharmony_ci } 162ffe3c632Sopenharmony_ci 163ffe3c632Sopenharmony_ci /// <summary> 164ffe3c632Sopenharmony_ci /// Reads a uint64 field from the input. 165ffe3c632Sopenharmony_ci /// </summary> 166ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 167ffe3c632Sopenharmony_ci public ulong ReadUInt64() 168ffe3c632Sopenharmony_ci { 169ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 170ffe3c632Sopenharmony_ci } 171ffe3c632Sopenharmony_ci 172ffe3c632Sopenharmony_ci /// <summary> 173ffe3c632Sopenharmony_ci /// Reads an int64 field from the input. 174ffe3c632Sopenharmony_ci /// </summary> 175ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 176ffe3c632Sopenharmony_ci public long ReadInt64() 177ffe3c632Sopenharmony_ci { 178ffe3c632Sopenharmony_ci return (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state); 179ffe3c632Sopenharmony_ci } 180ffe3c632Sopenharmony_ci 181ffe3c632Sopenharmony_ci /// <summary> 182ffe3c632Sopenharmony_ci /// Reads an int32 field from the input. 183ffe3c632Sopenharmony_ci /// </summary> 184ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 185ffe3c632Sopenharmony_ci public int ReadInt32() 186ffe3c632Sopenharmony_ci { 187ffe3c632Sopenharmony_ci return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 188ffe3c632Sopenharmony_ci } 189ffe3c632Sopenharmony_ci 190ffe3c632Sopenharmony_ci /// <summary> 191ffe3c632Sopenharmony_ci /// Reads a fixed64 field from the input. 192ffe3c632Sopenharmony_ci /// </summary> 193ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 194ffe3c632Sopenharmony_ci public ulong ReadFixed64() 195ffe3c632Sopenharmony_ci { 196ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 197ffe3c632Sopenharmony_ci } 198ffe3c632Sopenharmony_ci 199ffe3c632Sopenharmony_ci /// <summary> 200ffe3c632Sopenharmony_ci /// Reads a fixed32 field from the input. 201ffe3c632Sopenharmony_ci /// </summary> 202ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 203ffe3c632Sopenharmony_ci public uint ReadFixed32() 204ffe3c632Sopenharmony_ci { 205ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 206ffe3c632Sopenharmony_ci } 207ffe3c632Sopenharmony_ci 208ffe3c632Sopenharmony_ci /// <summary> 209ffe3c632Sopenharmony_ci /// Reads a bool field from the input. 210ffe3c632Sopenharmony_ci /// </summary> 211ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 212ffe3c632Sopenharmony_ci public bool ReadBool() 213ffe3c632Sopenharmony_ci { 214ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0; 215ffe3c632Sopenharmony_ci } 216ffe3c632Sopenharmony_ci /// <summary> 217ffe3c632Sopenharmony_ci /// Reads a string field from the input. 218ffe3c632Sopenharmony_ci /// </summary> 219ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 220ffe3c632Sopenharmony_ci public string ReadString() 221ffe3c632Sopenharmony_ci { 222ffe3c632Sopenharmony_ci return ParsingPrimitives.ReadString(ref buffer, ref state); 223ffe3c632Sopenharmony_ci } 224ffe3c632Sopenharmony_ci 225ffe3c632Sopenharmony_ci /// <summary> 226ffe3c632Sopenharmony_ci /// Reads an embedded message field value from the input. 227ffe3c632Sopenharmony_ci /// </summary> 228ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 229ffe3c632Sopenharmony_ci public void ReadMessage(IMessage message) 230ffe3c632Sopenharmony_ci { 231ffe3c632Sopenharmony_ci ParsingPrimitivesMessages.ReadMessage(ref this, message); 232ffe3c632Sopenharmony_ci } 233ffe3c632Sopenharmony_ci 234ffe3c632Sopenharmony_ci /// <summary> 235ffe3c632Sopenharmony_ci /// Reads an embedded group field from the input. 236ffe3c632Sopenharmony_ci /// </summary> 237ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 238ffe3c632Sopenharmony_ci public void ReadGroup(IMessage message) 239ffe3c632Sopenharmony_ci { 240ffe3c632Sopenharmony_ci ParsingPrimitivesMessages.ReadGroup(ref this, message); 241ffe3c632Sopenharmony_ci } 242ffe3c632Sopenharmony_ci 243ffe3c632Sopenharmony_ci /// <summary> 244ffe3c632Sopenharmony_ci /// Reads a bytes field value from the input. 245ffe3c632Sopenharmony_ci /// </summary> 246ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 247ffe3c632Sopenharmony_ci public ByteString ReadBytes() 248ffe3c632Sopenharmony_ci { 249ffe3c632Sopenharmony_ci return ParsingPrimitives.ReadBytes(ref buffer, ref state); 250ffe3c632Sopenharmony_ci } 251ffe3c632Sopenharmony_ci /// <summary> 252ffe3c632Sopenharmony_ci /// Reads a uint32 field value from the input. 253ffe3c632Sopenharmony_ci /// </summary> 254ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 255ffe3c632Sopenharmony_ci public uint ReadUInt32() 256ffe3c632Sopenharmony_ci { 257ffe3c632Sopenharmony_ci return ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 258ffe3c632Sopenharmony_ci } 259ffe3c632Sopenharmony_ci 260ffe3c632Sopenharmony_ci /// <summary> 261ffe3c632Sopenharmony_ci /// Reads an enum field value from the input. 262ffe3c632Sopenharmony_ci /// </summary> 263ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 264ffe3c632Sopenharmony_ci public int ReadEnum() 265ffe3c632Sopenharmony_ci { 266ffe3c632Sopenharmony_ci // Currently just a pass-through, but it's nice to separate it logically from WriteInt32. 267ffe3c632Sopenharmony_ci return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 268ffe3c632Sopenharmony_ci } 269ffe3c632Sopenharmony_ci 270ffe3c632Sopenharmony_ci /// <summary> 271ffe3c632Sopenharmony_ci /// Reads an sfixed32 field value from the input. 272ffe3c632Sopenharmony_ci /// </summary> 273ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 274ffe3c632Sopenharmony_ci public int ReadSFixed32() 275ffe3c632Sopenharmony_ci { 276ffe3c632Sopenharmony_ci return (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state); 277ffe3c632Sopenharmony_ci } 278ffe3c632Sopenharmony_ci 279ffe3c632Sopenharmony_ci /// <summary> 280ffe3c632Sopenharmony_ci /// Reads an sfixed64 field value from the input. 281ffe3c632Sopenharmony_ci /// </summary> 282ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 283ffe3c632Sopenharmony_ci public long ReadSFixed64() 284ffe3c632Sopenharmony_ci { 285ffe3c632Sopenharmony_ci return (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state); 286ffe3c632Sopenharmony_ci } 287ffe3c632Sopenharmony_ci 288ffe3c632Sopenharmony_ci /// <summary> 289ffe3c632Sopenharmony_ci /// Reads an sint32 field value from the input. 290ffe3c632Sopenharmony_ci /// </summary> 291ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 292ffe3c632Sopenharmony_ci public int ReadSInt32() 293ffe3c632Sopenharmony_ci { 294ffe3c632Sopenharmony_ci return ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state)); 295ffe3c632Sopenharmony_ci } 296ffe3c632Sopenharmony_ci 297ffe3c632Sopenharmony_ci /// <summary> 298ffe3c632Sopenharmony_ci /// Reads an sint64 field value from the input. 299ffe3c632Sopenharmony_ci /// </summary> 300ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 301ffe3c632Sopenharmony_ci public long ReadSInt64() 302ffe3c632Sopenharmony_ci { 303ffe3c632Sopenharmony_ci return ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state)); 304ffe3c632Sopenharmony_ci } 305ffe3c632Sopenharmony_ci 306ffe3c632Sopenharmony_ci /// <summary> 307ffe3c632Sopenharmony_ci /// Reads a length for length-delimited data. 308ffe3c632Sopenharmony_ci /// </summary> 309ffe3c632Sopenharmony_ci /// <remarks> 310ffe3c632Sopenharmony_ci /// This is internally just reading a varint, but this method exists 311ffe3c632Sopenharmony_ci /// to make the calling code clearer. 312ffe3c632Sopenharmony_ci /// </remarks> 313ffe3c632Sopenharmony_ci [MethodImpl(MethodImplOptions.AggressiveInlining)] 314ffe3c632Sopenharmony_ci public int ReadLength() 315ffe3c632Sopenharmony_ci { 316ffe3c632Sopenharmony_ci return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state); 317ffe3c632Sopenharmony_ci } 318ffe3c632Sopenharmony_ci 319ffe3c632Sopenharmony_ci internal void CopyStateTo(CodedInputStream input) 320ffe3c632Sopenharmony_ci { 321ffe3c632Sopenharmony_ci input.InternalState = state; 322ffe3c632Sopenharmony_ci } 323ffe3c632Sopenharmony_ci 324ffe3c632Sopenharmony_ci internal void LoadStateFrom(CodedInputStream input) 325ffe3c632Sopenharmony_ci { 326ffe3c632Sopenharmony_ci state = input.InternalState; 327ffe3c632Sopenharmony_ci } 328ffe3c632Sopenharmony_ci } 329ffe3c632Sopenharmony_ci}