GPBExtensionInternals.m 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. //
  4. // Use of this source code is governed by a BSD-style
  5. // license that can be found in the LICENSE file or at
  6. // https://developers.google.com/open-source/licenses/bsd
  7. #import "GPBExtensionInternals.h"
  8. #import <objc/runtime.h>
  9. #import "GPBCodedInputStream.h"
  10. #import "GPBCodedInputStream_PackagePrivate.h"
  11. #import "GPBCodedOutputStream.h"
  12. #import "GPBCodedOutputStream_PackagePrivate.h"
  13. #import "GPBDescriptor.h"
  14. #import "GPBDescriptor_PackagePrivate.h"
  15. #import "GPBMessage.h"
  16. #import "GPBMessage_PackagePrivate.h"
  17. #import "GPBUtilities.h"
  18. #import "GPBUtilities_PackagePrivate.h"
  19. GPB_INLINE size_t DataTypeSize(GPBDataType dataType) {
  20. #pragma clang diagnostic push
  21. #pragma clang diagnostic ignored "-Wswitch-enum"
  22. switch (dataType) {
  23. case GPBDataTypeBool:
  24. return 1;
  25. case GPBDataTypeFixed32:
  26. case GPBDataTypeSFixed32:
  27. case GPBDataTypeFloat:
  28. return 4;
  29. case GPBDataTypeFixed64:
  30. case GPBDataTypeSFixed64:
  31. case GPBDataTypeDouble:
  32. return 8;
  33. default:
  34. return 0;
  35. }
  36. #pragma clang diagnostic pop
  37. }
  38. static size_t ComputePBSerializedSizeNoTagOfObject(GPBDataType dataType, id object) {
  39. #define FIELD_CASE(TYPE, ACCESSOR) \
  40. case GPBDataType##TYPE: \
  41. return GPBCompute##TYPE##SizeNoTag([(NSNumber *)object ACCESSOR]);
  42. #define FIELD_CASE2(TYPE) \
  43. case GPBDataType##TYPE: \
  44. return GPBCompute##TYPE##SizeNoTag(object);
  45. switch (dataType) {
  46. FIELD_CASE(Bool, boolValue)
  47. FIELD_CASE(Float, floatValue)
  48. FIELD_CASE(Double, doubleValue)
  49. FIELD_CASE(Int32, intValue)
  50. FIELD_CASE(SFixed32, intValue)
  51. FIELD_CASE(SInt32, intValue)
  52. FIELD_CASE(Enum, intValue)
  53. FIELD_CASE(Int64, longLongValue)
  54. FIELD_CASE(SInt64, longLongValue)
  55. FIELD_CASE(SFixed64, longLongValue)
  56. FIELD_CASE(UInt32, unsignedIntValue)
  57. FIELD_CASE(Fixed32, unsignedIntValue)
  58. FIELD_CASE(UInt64, unsignedLongLongValue)
  59. FIELD_CASE(Fixed64, unsignedLongLongValue)
  60. FIELD_CASE2(Bytes)
  61. FIELD_CASE2(String)
  62. FIELD_CASE2(Message)
  63. FIELD_CASE2(Group)
  64. }
  65. #undef FIELD_CASE
  66. #undef FIELD_CASE2
  67. }
  68. static size_t ComputeSerializedSizeIncludingTagOfObject(GPBExtensionDescription *description,
  69. id object) {
  70. #define FIELD_CASE(TYPE, ACCESSOR) \
  71. case GPBDataType##TYPE: \
  72. return GPBCompute##TYPE##Size(description->fieldNumber, [(NSNumber *)object ACCESSOR]);
  73. #define FIELD_CASE2(TYPE) \
  74. case GPBDataType##TYPE: \
  75. return GPBCompute##TYPE##Size(description->fieldNumber, object);
  76. switch (description->dataType) {
  77. FIELD_CASE(Bool, boolValue)
  78. FIELD_CASE(Float, floatValue)
  79. FIELD_CASE(Double, doubleValue)
  80. FIELD_CASE(Int32, intValue)
  81. FIELD_CASE(SFixed32, intValue)
  82. FIELD_CASE(SInt32, intValue)
  83. FIELD_CASE(Enum, intValue)
  84. FIELD_CASE(Int64, longLongValue)
  85. FIELD_CASE(SInt64, longLongValue)
  86. FIELD_CASE(SFixed64, longLongValue)
  87. FIELD_CASE(UInt32, unsignedIntValue)
  88. FIELD_CASE(Fixed32, unsignedIntValue)
  89. FIELD_CASE(UInt64, unsignedLongLongValue)
  90. FIELD_CASE(Fixed64, unsignedLongLongValue)
  91. FIELD_CASE2(Bytes)
  92. FIELD_CASE2(String)
  93. FIELD_CASE2(Group)
  94. case GPBDataTypeMessage:
  95. if (GPBExtensionIsWireFormat(description)) {
  96. return GPBComputeMessageSetExtensionSize(description->fieldNumber, object);
  97. } else {
  98. return GPBComputeMessageSize(description->fieldNumber, object);
  99. }
  100. }
  101. #undef FIELD_CASE
  102. #undef FIELD_CASE2
  103. }
  104. static size_t ComputeSerializedSizeIncludingTagOfArray(GPBExtensionDescription *description,
  105. NSArray *values) {
  106. if (GPBExtensionIsPacked(description)) {
  107. size_t size = 0;
  108. size_t typeSize = DataTypeSize(description->dataType);
  109. if (typeSize != 0) {
  110. size = values.count * typeSize;
  111. } else {
  112. for (id value in values) {
  113. size += ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
  114. }
  115. }
  116. return size + GPBComputeTagSize(description->fieldNumber) +
  117. GPBComputeRawVarint32SizeForInteger(size);
  118. } else {
  119. size_t size = 0;
  120. for (id value in values) {
  121. size += ComputeSerializedSizeIncludingTagOfObject(description, value);
  122. }
  123. return size;
  124. }
  125. }
  126. static void WriteObjectIncludingTagToCodedOutputStream(id object,
  127. GPBExtensionDescription *description,
  128. GPBCodedOutputStream *output) {
  129. #define FIELD_CASE(TYPE, ACCESSOR) \
  130. case GPBDataType##TYPE: \
  131. [output write##TYPE:description->fieldNumber value:[(NSNumber *)object ACCESSOR]]; \
  132. return;
  133. #define FIELD_CASE2(TYPE) \
  134. case GPBDataType##TYPE: \
  135. [output write##TYPE:description->fieldNumber value:object]; \
  136. return;
  137. switch (description->dataType) {
  138. FIELD_CASE(Bool, boolValue)
  139. FIELD_CASE(Float, floatValue)
  140. FIELD_CASE(Double, doubleValue)
  141. FIELD_CASE(Int32, intValue)
  142. FIELD_CASE(SFixed32, intValue)
  143. FIELD_CASE(SInt32, intValue)
  144. FIELD_CASE(Enum, intValue)
  145. FIELD_CASE(Int64, longLongValue)
  146. FIELD_CASE(SInt64, longLongValue)
  147. FIELD_CASE(SFixed64, longLongValue)
  148. FIELD_CASE(UInt32, unsignedIntValue)
  149. FIELD_CASE(Fixed32, unsignedIntValue)
  150. FIELD_CASE(UInt64, unsignedLongLongValue)
  151. FIELD_CASE(Fixed64, unsignedLongLongValue)
  152. FIELD_CASE2(Bytes)
  153. FIELD_CASE2(String)
  154. FIELD_CASE2(Group)
  155. case GPBDataTypeMessage:
  156. if (GPBExtensionIsWireFormat(description)) {
  157. [output writeMessageSetExtension:description->fieldNumber value:object];
  158. } else {
  159. [output writeMessage:description->fieldNumber value:object];
  160. }
  161. return;
  162. }
  163. #undef FIELD_CASE
  164. #undef FIELD_CASE2
  165. }
  166. static void WriteObjectNoTagToCodedOutputStream(id object, GPBExtensionDescription *description,
  167. GPBCodedOutputStream *output) {
  168. #define FIELD_CASE(TYPE, ACCESSOR) \
  169. case GPBDataType##TYPE: \
  170. [output write##TYPE##NoTag:[(NSNumber *)object ACCESSOR]]; \
  171. return;
  172. #define FIELD_CASE2(TYPE) \
  173. case GPBDataType##TYPE: \
  174. [output write##TYPE##NoTag:object]; \
  175. return;
  176. switch (description->dataType) {
  177. FIELD_CASE(Bool, boolValue)
  178. FIELD_CASE(Float, floatValue)
  179. FIELD_CASE(Double, doubleValue)
  180. FIELD_CASE(Int32, intValue)
  181. FIELD_CASE(SFixed32, intValue)
  182. FIELD_CASE(SInt32, intValue)
  183. FIELD_CASE(Enum, intValue)
  184. FIELD_CASE(Int64, longLongValue)
  185. FIELD_CASE(SInt64, longLongValue)
  186. FIELD_CASE(SFixed64, longLongValue)
  187. FIELD_CASE(UInt32, unsignedIntValue)
  188. FIELD_CASE(Fixed32, unsignedIntValue)
  189. FIELD_CASE(UInt64, unsignedLongLongValue)
  190. FIELD_CASE(Fixed64, unsignedLongLongValue)
  191. FIELD_CASE2(Bytes)
  192. FIELD_CASE2(String)
  193. FIELD_CASE2(Message)
  194. case GPBDataTypeGroup:
  195. [output writeGroupNoTag:description->fieldNumber value:object];
  196. return;
  197. }
  198. #undef FIELD_CASE
  199. #undef FIELD_CASE2
  200. }
  201. static void WriteArrayIncludingTagsToCodedOutputStream(NSArray *values,
  202. GPBExtensionDescription *description,
  203. GPBCodedOutputStream *output) {
  204. if (GPBExtensionIsPacked(description)) {
  205. [output writeTag:description->fieldNumber format:GPBWireFormatLengthDelimited];
  206. size_t dataSize = 0;
  207. size_t typeSize = DataTypeSize(description->dataType);
  208. if (typeSize != 0) {
  209. dataSize = values.count * typeSize;
  210. } else {
  211. for (id value in values) {
  212. dataSize += ComputePBSerializedSizeNoTagOfObject(description->dataType, value);
  213. }
  214. }
  215. [output writeRawVarintSizeTAs32:dataSize];
  216. for (id value in values) {
  217. WriteObjectNoTagToCodedOutputStream(value, description, output);
  218. }
  219. } else {
  220. for (id value in values) {
  221. WriteObjectIncludingTagToCodedOutputStream(value, description, output);
  222. }
  223. }
  224. }
  225. // Direct access is use for speed, to avoid even internally declaring things
  226. // read/write, etc. The warning is enabled in the project to ensure code calling
  227. // protos can turn on -Wdirect-ivar-access without issues.
  228. #pragma clang diagnostic push
  229. #pragma clang diagnostic ignored "-Wdirect-ivar-access"
  230. void GPBWriteExtensionValueToOutputStream(GPBExtensionDescriptor *extension, id value,
  231. GPBCodedOutputStream *output) {
  232. GPBExtensionDescription *description = extension->description_;
  233. if (GPBExtensionIsRepeated(description)) {
  234. WriteArrayIncludingTagsToCodedOutputStream(value, description, output);
  235. } else {
  236. WriteObjectIncludingTagToCodedOutputStream(value, description, output);
  237. }
  238. }
  239. size_t GPBComputeExtensionSerializedSizeIncludingTag(GPBExtensionDescriptor *extension, id value) {
  240. GPBExtensionDescription *description = extension->description_;
  241. if (GPBExtensionIsRepeated(description)) {
  242. return ComputeSerializedSizeIncludingTagOfArray(description, value);
  243. } else {
  244. return ComputeSerializedSizeIncludingTagOfObject(description, value);
  245. }
  246. }
  247. #pragma clang diagnostic pop