1  /*
2   * Copyright (C) 2021 Huawei Device Co., Ltd.
3   * Licensed under the Apache License, Version 2.0 (the "License");
4   * you may not use this file except in compliance with the License.
5   * You may obtain a copy of the License at
6   *
7   *     http://www.apache.org/licenses/LICENSE-2.0
8   *
9   * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  #include "mms_content_type.h"
16  
17  #include "telephony_log_wrapper.h"
18  #include "mms_decode_buffer.h"
19  #include "mms_charset.h"
20  
21  namespace OHOS {
22  namespace Telephony {
DumpMmsContentType()23  void MmsContentType::DumpMmsContentType()
24  {
25      TELEPHONY_LOGI("contentType : %{public}s", contentType_.c_str());
26      msgContentParm_.DumpContentParam();
27  }
28  
MmsContentType(const MmsContentType & srcContentType)29  MmsContentType::MmsContentType(const MmsContentType &srcContentType)
30  {
31      contentType_ = srcContentType.contentType_;
32      msgContentParm_ = srcContentType.msgContentParm_;
33  }
34  
operator =(const MmsContentType & srcContentType)35  MmsContentType &MmsContentType::operator=(const MmsContentType &srcContentType)
36  {
37      if (this != &srcContentType) {
38          contentType_ = srcContentType.contentType_;
39          msgContentParm_ = srcContentType.msgContentParm_;
40      }
41      return *this;
42  }
43  
44  /**
45   * @brief DecodeMmsContentType
46   * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
47   * Content-type-value = Constrained-media | Content-general-form
48   * Constrained-media = Constrained-encoding
49   * Constrained-encoding = Extension-Media | Short-integer
50   * Extension-media = *TEXT End-of-string
51   * Content-general-form = Value-length Media-type
52   * Media-type = (Well-known-media | Extension-Media) *(Parameter)
53   * Well-known-media = Integer-value
54   * Parameter = Typed-parameter | Untyped-parameter
55   * @param decodeBuffer
56   * @param contentLength
57   * @return true
58   * @return false
59   */
DecodeMmsContentType(MmsDecodeBuffer & decodeBuffer,int32_t & contentLength)60  bool MmsContentType::DecodeMmsContentType(MmsDecodeBuffer &decodeBuffer, int32_t &contentLength)
61  {
62      const uint8_t setHighestBitZero = 0x7f;
63      uint8_t oneByte = 0;
64      if (decodeBuffer.DecodeIsShortInt()) {
65          if (!decodeBuffer.GetOneByte(oneByte)) {
66              TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
67              return false;
68          }
69          contentType_ = GetContentTypeFromInt(oneByte & setHighestBitZero);
70          contentLength = 1;
71          return true;
72      }
73  
74      if (decodeBuffer.DecodeIsString()) {
75          std::string sType = "";
76          uint32_t len = 0;
77          decodeBuffer.DecodeText(sType, len);
78          contentLength = static_cast<int32_t>(len + 1);
79          contentType_ = sType;
80          return true; // 2
81      }
82  
83      if (!DecodeMmsCTGeneralForm(decodeBuffer, contentLength)) {
84          TELEPHONY_LOGE("Decode contentType DecodeMmsCTGeneralForm fail.");
85          return false;
86      }
87      return true;
88  }
89  
90  /**
91   * @brief DecodeMmsCTGeneralForm
92   * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
93   * Content-type-value = Constrained-media | Content-general-form
94   * Constrained-media = Constrained-encoding
95   * Constrained-encoding = Extension-Media | Short-integer
96   * Extension-media = *TEXT End-of-string
97   * Content-general-form = Value-length Media-type
98   * Media-type = (Well-known-media | Extension-Media) *(Parameter)
99   * Well-known-media = Integer-value
100   * Parameter = Typed-parameter | Untyped-parameter
101   * @param decodeBuffer
102   * @param contentLength
103   * @return true
104   * @return false
105   */
DecodeMmsCTGeneralForm(MmsDecodeBuffer & decodeBuffer,int32_t & contentLength)106  bool MmsContentType::DecodeMmsCTGeneralForm(MmsDecodeBuffer &decodeBuffer, int32_t &contentLength)
107  {
108      const uint8_t setHighestBitZero = 0x7f;
109  
110     /** false indicated no more data */
111      if (!decodeBuffer.DecodeIsValueLength()) {
112          TELEPHONY_LOGE("Decode contentType DecodeIsValueLength fail.");
113          return false;
114      }
115  
116      uint32_t valueLength = 0;
117      uint32_t returnLength = 0;
118      if (!decodeBuffer.DecodeValueLengthReturnLen(valueLength, returnLength)) {
119          TELEPHONY_LOGE("Decode contentType DecodeValueLengthReturnLen fail.");
120          return false;
121      }
122      contentLength = static_cast<int32_t>(valueLength + returnLength);
123  
124      uint8_t oneByte = 0;
125      if (!decodeBuffer.PeekOneByte(oneByte)) {
126          TELEPHONY_LOGE("Decode contentType PeekOneByte fail.");
127          return false;
128      }
129      if (decodeBuffer.DecodeIsShortInt()) {
130          contentType_ = GetContentTypeFromInt(oneByte & setHighestBitZero);
131          if (!decodeBuffer.IncreasePointer(1)) {
132              TELEPHONY_LOGE("Decode contentType IncreasePointer fail.");
133              return false;
134          }
135          if (valueLength == 0) {
136              TELEPHONY_LOGE("Decode contentType valueLength empty.");
137              return false;
138          }
139          valueLength--;
140      } else if (decodeBuffer.DecodeIsString()) {
141          std::string sType = "";
142          uint32_t len = 0;
143          decodeBuffer.DecodeText(sType, len);
144          valueLength -= len + 1;
145          contentType_ = sType;
146      } else {
147          TELEPHONY_LOGE("Decode contentType DecodeMmsContentType fail.");
148          return false;
149      }
150  
151      if (!DecodeParameter(decodeBuffer, valueLength)) {
152          TELEPHONY_LOGE("Decode contentType DecodeParameter fail.");
153          return false;
154      }
155      return true;
156  }
157  
GetContentTypeFromInt(uint8_t type)158  std::string MmsContentType::GetContentTypeFromInt(uint8_t type)
159  {
160      for (unsigned int i = 0; i < sizeof(mmsContentNames) / sizeof(mmsContentNames[0]); i++) {
161          if (type == static_cast<uint8_t>(mmsContentNames[i].key)) {
162              return mmsContentNames[i].value;
163          }
164      }
165      return "*/*";
166  }
167  
GetContentTypeFromString(std::string str)168  int8_t MmsContentType::GetContentTypeFromString(std::string str)
169  {
170      for (unsigned int i = 0; i < sizeof(mmsContentNames) / sizeof(mmsContentNames[0]); i++) {
171          if (str == std::string(mmsContentNames[i].value)) {
172              return i;
173          }
174      }
175      return -1;
176  }
177  
178  /**
179   * @brief DecodeParameter
180   * wap-230-wsp-20010705-a   section:8.4.2.4 Parameter
181   * Parameter = Typed-parameter | Untyped-parameter
182   * Typed-parameter = Well-known-parameter-token Typed-value
183   * Well-known-parameter-token = Integer-value
184   * Typed-value = Compact-value | Text-value
185   * Compact-value = Integer-value |
186   *                 Date-value | Delta-seconds-value | Q-value | Version-value |
187   *                 Uri-value
188   * Untyped-parameter = Token-text Untyped-value
189   * Untyped-value = Integer-value | Text-value
190   * Delta-seconds-value = Long-integer
191   * Q-value = 1*2 OCTET
192   * @param decodeBuffer
193   * @param valueLength
194   * @return true
195   * @return false
196   */
DecodeParameter(MmsDecodeBuffer & decodeBuffer,int32_t valueLength)197  bool MmsContentType::DecodeParameter(MmsDecodeBuffer &decodeBuffer, int32_t valueLength)
198  {
199      uint8_t paramCode = 0;
200      while (valueLength > 0) {
201          if (!decodeBuffer.GetOneByte(paramCode)) {
202              TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
203              return false;
204          }
205          valueLength--;
206          switch (static_cast<ContentParam>(paramCode)) {
207              case ContentParam::CT_P_CHARSET: {
208                  /* charset */
209                  if (!DecodeCharsetField(decodeBuffer, valueLength)) {
210                      TELEPHONY_LOGE("Decode contentType DecodeCharsetField fail.");
211                      return false;
212                  }
213                  break;
214              }
215              case ContentParam::CT_P_FILENAME:
216              case ContentParam::CT_P_FILENAME_VALUE:
217              case ContentParam::CT_P_START_VALUE:
218              case ContentParam::CT_P_START:
219              case ContentParam::CT_P_NAME:
220              case ContentParam::CT_P_NAME_VALUE:
221              case ContentParam::CT_P_START_INFO:
222              case ContentParam::CT_P_START_INFO_VALUE: {
223                  if (!DecodeTextField(decodeBuffer, paramCode, valueLength)) {
224                      TELEPHONY_LOGE("Decode contentType DecodeTextField fail.");
225                      return false;
226                  }
227                  break;
228              }
229              case ContentParam::CT_P_TYPE:
230              case ContentParam::CT_P_TYPE_STRING: {
231                  if (!DecodeTypeField(decodeBuffer, valueLength)) {
232                      TELEPHONY_LOGE("Decode contentType DecodeTypeField fail.");
233                      return false;
234                  }
235                  break;
236              }
237              default: {
238                  if (!decodeBuffer.IncreasePointer(valueLength)) {
239                      TELEPHONY_LOGE("Decode contentType IncreasePointer fail.");
240                      return false;
241                  }
242                  valueLength = 0;
243              }
244          }
245      }
246      return true;
247  }
248  
GetContentType(std::string & str)249  bool MmsContentType::GetContentType(std::string &str)
250  {
251      str = contentType_;
252      return true;
253  }
254  
SetContentType(std::string str)255  bool MmsContentType::SetContentType(std::string str)
256  {
257      contentType_ = str;
258      return true;
259  }
260  
SetContentParam(MmsContentParam & contentParam)261  bool MmsContentType::SetContentParam(MmsContentParam &contentParam)
262  {
263      msgContentParm_ = contentParam;
264      return true;
265  }
266  
267  /**
268   * @brief DecodeTextField
269   * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
270   * Text-string = [Quote] *TEXT End-of-string
271   * Quote = <Octet 127>
272   * End-of-string = <Octet 0>
273   * @param decodeBuffer
274   * @param field
275   * @param valueLength
276   * @return true
277   * @return false
278   */
DecodeTextField(MmsDecodeBuffer & decodeBuffer,uint8_t field,int32_t & valueLength)279  bool MmsContentType::DecodeTextField(MmsDecodeBuffer &decodeBuffer, uint8_t field, int32_t &valueLength)
280  {
281      std::string str = "";
282      uint32_t len = 0;
283      if (!decodeBuffer.DecodeText(str, len)) {
284          TELEPHONY_LOGE("Decode contentType DecodeText fail.");
285          return false;
286      }
287      msgContentParm_.GetParamMap().insert(std::make_pair(field, str));
288      valueLength -= static_cast<int32_t>(len);
289      valueLength -= 1;
290      return true;
291  }
292  
293  /**
294   * @brief DecodeCharsetField
295   * wap-230-wsp-20010705-a   section:8.4.2.8 Accept charset field
296   * Well-known-charset = Any-charset | Integer-value
297   * Any-charset = <Octet 128>
298   * @param decodeBuffer
299   * @param valueLength
300   * @return true
301   * @return false
302   */
DecodeCharsetField(MmsDecodeBuffer & decodeBuffer,int32_t & valueLength)303  bool MmsContentType::DecodeCharsetField(MmsDecodeBuffer &decodeBuffer, int32_t &valueLength)
304  {
305      int32_t charset = 0;
306      uint8_t oneByte = 0;
307      const uint8_t textMinValue = 32;
308      const uint8_t textMaxValue = 127;
309      if (decodeBuffer.PeekOneByte(oneByte) == false) {
310          TELEPHONY_LOGE("Decode contentType PeekOneByte fail.");
311          return false;
312      }
313      if (((oneByte > textMinValue) && (oneByte < textMaxValue)) || (oneByte == 0)) {
314          std::string sCharset = "";
315          uint32_t len = 0;
316          if (!decodeBuffer.DecodeText(sCharset, len)) {
317              TELEPHONY_LOGE("Decode contentType DecodeText fail.");
318              return false;
319          }
320          valueLength -= static_cast<int32_t>(len + 1);
321          uint32_t tmpCharSet = 0;
322          auto charSetInstance = DelayedSingleton<MmsCharSet>::GetInstance();
323          if (charSetInstance == nullptr || (!charSetInstance->GetCharSetIntFromString(tmpCharSet, sCharset))) {
324              TELEPHONY_LOGE("Decode contentType GetInstance or GetCharSetIntFromString fail.");
325              return false;
326          }
327          charset = static_cast<int32_t>(tmpCharSet);
328      } else {
329          uint32_t startPosition = decodeBuffer.GetCurPosition();
330          uint64_t tmp = 0;
331          if (!decodeBuffer.DecodeInteger(tmp)) {
332              TELEPHONY_LOGE("Decode contentType DecodeInteger fail.");
333              return false;
334          }
335          charset = (int32_t)tmp;
336          uint32_t endPosition = decodeBuffer.GetCurPosition();
337          if (endPosition >= startPosition) {
338              valueLength -= static_cast<int32_t>(endPosition - startPosition);
339          }
340      }
341      msgContentParm_.SetCharSet(charset);
342      return true;
343  }
344  
345  /**
346   * @brief DecodeTypeField
347   * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
348   * Constrained-encoding = Extension-Media | Short-integer
349   * Extension-media = *TEXT End-of-string
350   * @param decodeBuffer
351   * @param valueLength
352   * @return true
353   * @return false
354   */
DecodeTypeField(MmsDecodeBuffer & decodeBuffer,int32_t & valueLength)355  bool MmsContentType::DecodeTypeField(MmsDecodeBuffer &decodeBuffer, int32_t &valueLength)
356  {
357      uint8_t oneByte = 0;
358      if (decodeBuffer.GetOneByte(oneByte) == false) {
359          TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
360          return false;
361      }
362  
363      if (oneByte > 0x7f) {
364          msgContentParm_.SetType(GetContentTypeFromInt(oneByte & 0x7f));
365          valueLength -= 1;
366      } else {
367          if (!decodeBuffer.DecreasePointer(1)) {
368              TELEPHONY_LOGE("Decode contentType DecreasePointer fail.");
369              return false;
370          }
371  
372          std::string sType = "";
373          uint32_t len = 0;
374          if (!decodeBuffer.DecodeText(sType, len)) {
375              TELEPHONY_LOGE("Decode contentType DecodeText fail.");
376              return false;
377          }
378          valueLength -= static_cast<int32_t>(len);
379          valueLength -= 1;
380          msgContentParm_.SetType(sType);
381      }
382      return true;
383  }
384  
385  /**
386   * @brief EncodeTextField
387   * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
388   * Text-string = [Quote] *TEXT End-of-string
389   * Quote = <Octet 127>
390   * End-of-string = <Octet 0>
391   * @param encodeBuffer
392   * @return true
393   * @return false
394   */
EncodeTextField(MmsEncodeBuffer & encodeBuffer)395  bool MmsContentType::EncodeTextField(MmsEncodeBuffer &encodeBuffer)
396  {
397      const uint8_t textParamLen = 8;
398      uint8_t fields[textParamLen] = {static_cast<uint8_t>(ContentParam::CT_P_FILENAME),
399          static_cast<uint8_t>(ContentParam::CT_P_FILENAME_VALUE),
400          static_cast<uint8_t>(ContentParam::CT_P_START_VALUE), static_cast<uint8_t>(ContentParam::CT_P_START),
401          static_cast<uint8_t>(ContentParam::CT_P_NAME), static_cast<uint8_t>(ContentParam::CT_P_NAME_VALUE),
402          static_cast<uint8_t>(ContentParam::CT_P_START_INFO),
403          static_cast<uint8_t>(ContentParam::CT_P_START_INFO_VALUE)};
404  
405      for (size_t i = 0; i < sizeof(fields); i++) {
406          if (msgContentParm_.GetParamMap().find(fields[i]) != msgContentParm_.GetParamMap().end()) {
407              if (!encodeBuffer.WriteByte(fields[i])) {
408                  TELEPHONY_LOGE("Encode contentType WriteByte fail.");
409                  return false;
410              }
411              if (!encodeBuffer.EncodeText(msgContentParm_.GetParamMap()[fields[i]])) {
412                  TELEPHONY_LOGE("Encode contentType EncodeText fail.");
413                  return false;
414              }
415          }
416      }
417      return true;
418  }
419  
420  /**
421   * @brief EncodeCharsetField
422   * wap-230-wsp-20010705-a   section:8.4.2.8 Accept charset field
423   * Well-known-charset = Any-charset | Integer-value
424   * Any-charset = <Octet 128>
425   * @param encodeBuffer
426   * @return true
427   * @return false
428   */
EncodeCharsetField(MmsEncodeBuffer & encodeBuffer)429  bool MmsContentType::EncodeCharsetField(MmsEncodeBuffer &encodeBuffer)
430  {
431      if (msgContentParm_.GetCharSet() == 0) {
432          return true;
433      }
434      if (!encodeBuffer.WriteByte(static_cast<uint8_t>(ContentParam::CT_P_CHARSET))) {
435          TELEPHONY_LOGE("Encode contentType WriteByte fail.");
436          return false;
437      }
438      if (!encodeBuffer.EncodeLongInteger(msgContentParm_.GetCharSet())) {
439          TELEPHONY_LOGE("Encode contentType EncodeLongInteger fail.");
440          return false;
441      }
442      return true;
443  }
444  
445  /**
446   * @brief EncodeTypeField
447   * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
448   * Constrained-encoding = Extension-Media | Short-integer
449   * Extension-media = *TEXT End-of-string
450   * @param encodeBuffer
451   * @return true
452   * @return false
453   */
EncodeTypeField(MmsEncodeBuffer & encodeBuffer)454  bool MmsContentType::EncodeTypeField(MmsEncodeBuffer &encodeBuffer)
455  {
456      if (msgContentParm_.GetType().empty()) {
457          return true;
458      }
459      if (!encodeBuffer.WriteByte(static_cast<uint8_t>(ContentParam::CT_P_TYPE))) {
460          TELEPHONY_LOGE("Encode contentType WriteByte fail.");
461          return false;
462      }
463      if (!encodeBuffer.EncodeText(msgContentParm_.GetType())) {
464          TELEPHONY_LOGE("Encode contentType EncodeText fail.");
465          return false;
466      }
467      return true;
468  }
469  
470  /**
471   * @brief EncodeMmsBodyPartContentParam
472   * wap-230-wsp-20010705-a   section:8.4.2.4 Parameter
473   * Parameter = Typed-parameter | Untyped-parameter
474   * Typed-parameter = Well-known-parameter-token Typed-value
475   * Well-known-parameter-token = Integer-value
476   * Typed-value = Compact-value | Text-value
477   * Compact-value = Integer-value |
478   *                 Date-value | Delta-seconds-value | Q-value | Version-value |
479   *                 Uri-value
480   * Untyped-parameter = Token-text Untyped-value
481   * Untyped-value = Integer-value | Text-value
482   * @param encodeBuffer
483   * @return true
484   * @return false
485   */
EncodeMmsBodyPartContentParam(MmsEncodeBuffer & encodeBuffer)486  bool MmsContentType::EncodeMmsBodyPartContentParam(MmsEncodeBuffer &encodeBuffer)
487  {
488      if (!EncodeTextField(encodeBuffer)) {
489          TELEPHONY_LOGE("Encode contentType EncodeTextField fail.");
490          return false;
491      }
492      if (!EncodeCharsetField(encodeBuffer)) {
493          TELEPHONY_LOGE("Encode contentType EncodeCharsetField fail.");
494          return false;
495      }
496      if (!EncodeTypeField(encodeBuffer)) {
497          TELEPHONY_LOGE("Encode contentType EncodeTypeField fail.");
498          return false;
499      }
500      return true;
501  }
502  
503  /**
504   * @brief EncodeMmsBodyPartContentType
505   * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
506   * Content-type-value = Constrained-media | Content-general-form
507   * Constrained-media = Constrained-encoding
508   * Constrained-encoding = Extension-Media | Short-integer
509   * Extension-media = *TEXT End-of-string
510   * Content-general-form = Value-length Media-type
511   * Media-type = (Well-known-media | Extension-Media) *(Parameter)
512   * Well-known-media = Integer-value
513   * Parameter = Typed-parameter | Untyped-parameter
514   * @param encodeBuffer
515   * @return true
516   * @return false
517   */
EncodeMmsBodyPartContentType(MmsEncodeBuffer & encodeBuffer)518  bool MmsContentType::EncodeMmsBodyPartContentType(MmsEncodeBuffer &encodeBuffer)
519  {
520      MmsEncodeBuffer tmpEncodeBuffer;
521      int8_t u8ContentType = 0;
522      u8ContentType = GetContentTypeFromString(contentType_);
523      if (u8ContentType < 0) {
524          if (!tmpEncodeBuffer.EncodeText(contentType_)) {
525              TELEPHONY_LOGE("Encode contentType EncodeText fail.");
526              return false;
527          }
528      } else {
529          if (!tmpEncodeBuffer.WriteByte(static_cast<uint8_t>(u8ContentType) | 0x80)) {
530              TELEPHONY_LOGE("Encode contentType WriteByte fail.");
531              return false;
532          }
533      }
534      if (!EncodeMmsBodyPartContentParam(tmpEncodeBuffer)) {
535          TELEPHONY_LOGE("Encode contentType EncodeMmsBodyPartContentParam fail.");
536          return false;
537      }
538      if (!encodeBuffer.EncodeValueLength(tmpEncodeBuffer.GetCurPosition())) {
539          TELEPHONY_LOGE("Encode contentType EncodeValueLength fail.");
540          return false;
541      }
542      if (!encodeBuffer.WriteBuffer(tmpEncodeBuffer)) {
543          TELEPHONY_LOGE("Encode contentType WriteBuffer fail.");
544          return false;
545      }
546      return true;
547  }
548  
GetContentParam()549  MmsContentParam& MmsContentType::GetContentParam()
550  {
551      return msgContentParm_;
552  }
553  } // namespace Telephony
554  } // namespace OHOS
555