GPBExtensionInternals.m 9.1 KB

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