TextFormatEncoder.swift 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Sources/SwiftProtobuf/TextFormatEncoder.swift - Text format encoding support
  2. //
  3. // Copyright (c) 2014 - 2019 Apple Inc. and the project authors
  4. // Licensed under Apache License v2.0 with Runtime Library Exception
  5. //
  6. // See LICENSE.txt for license information:
  7. // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
  8. //
  9. // -----------------------------------------------------------------------------
  10. ///
  11. /// Text format serialization engine.
  12. ///
  13. // -----------------------------------------------------------------------------
  14. import Foundation
  15. private let asciiSpace = UInt8(ascii: " ")
  16. private let asciiColon = UInt8(ascii: ":")
  17. private let asciiComma = UInt8(ascii: ",")
  18. private let asciiMinus = UInt8(ascii: "-")
  19. private let asciiBackslash = UInt8(ascii: "\\")
  20. private let asciiDoubleQuote = UInt8(ascii: "\"")
  21. private let asciiZero = UInt8(ascii: "0")
  22. private let asciiOpenCurlyBracket = UInt8(ascii: "{")
  23. private let asciiCloseCurlyBracket = UInt8(ascii: "}")
  24. private let asciiOpenSquareBracket = UInt8(ascii: "[")
  25. private let asciiCloseSquareBracket = UInt8(ascii: "]")
  26. private let asciiNewline = UInt8(ascii: "\n")
  27. private let asciiUpperA = UInt8(ascii: "A")
  28. private let tabSize = 2
  29. private let tab = [UInt8](repeating: asciiSpace, count: tabSize)
  30. /// TextFormatEncoder has no public members.
  31. internal struct TextFormatEncoder {
  32. private var data = [UInt8]()
  33. private var indentString: [UInt8] = []
  34. var stringResult: String {
  35. get {
  36. String(decoding: data, as: UTF8.self)
  37. }
  38. }
  39. internal mutating func append(staticText: StaticString) {
  40. let buff = UnsafeBufferPointer(start: staticText.utf8Start, count: staticText.utf8CodeUnitCount)
  41. data.append(contentsOf: buff)
  42. }
  43. internal mutating func append(name: _NameMap.Name) {
  44. data.append(contentsOf: name.utf8Buffer)
  45. }
  46. internal mutating func append(bytes: [UInt8]) {
  47. data.append(contentsOf: bytes)
  48. }
  49. private mutating func append(text: String) {
  50. data.append(contentsOf: text.utf8)
  51. }
  52. init() {}
  53. internal mutating func indent() {
  54. data.append(contentsOf: indentString)
  55. }
  56. mutating func emitFieldName(name: UnsafeRawBufferPointer) {
  57. indent()
  58. data.append(contentsOf: name)
  59. }
  60. mutating func emitFieldName(name: StaticString) {
  61. let buff = UnsafeRawBufferPointer(start: name.utf8Start, count: name.utf8CodeUnitCount)
  62. emitFieldName(name: buff)
  63. }
  64. mutating func emitFieldName(name: [UInt8]) {
  65. indent()
  66. data.append(contentsOf: name)
  67. }
  68. mutating func emitExtensionFieldName(name: String) {
  69. indent()
  70. data.append(asciiOpenSquareBracket)
  71. append(text: name)
  72. data.append(asciiCloseSquareBracket)
  73. }
  74. mutating func emitFieldNumber(number: Int) {
  75. indent()
  76. appendUInt(value: UInt64(number))
  77. }
  78. mutating func startRegularField() {
  79. append(staticText: ": ")
  80. }
  81. mutating func endRegularField() {
  82. data.append(asciiNewline)
  83. }
  84. // In Text format, a message-valued field writes the name
  85. // without a trailing colon:
  86. // name_of_field {key: value key2: value2}
  87. mutating func startMessageField() {
  88. append(staticText: " {\n")
  89. indentString.append(contentsOf: tab)
  90. }
  91. mutating func endMessageField() {
  92. indentString.removeLast(tabSize)
  93. indent()
  94. append(staticText: "}\n")
  95. }
  96. mutating func startArray() {
  97. data.append(asciiOpenSquareBracket)
  98. }
  99. mutating func arraySeparator() {
  100. append(staticText: ", ")
  101. }
  102. mutating func endArray() {
  103. data.append(asciiCloseSquareBracket)
  104. }
  105. mutating func putEnumValue<E: Enum>(value: E) {
  106. if let name = value.name {
  107. data.append(contentsOf: name.utf8Buffer)
  108. } else {
  109. appendInt(value: Int64(value.rawValue))
  110. }
  111. }
  112. mutating func putFloatValue(value: Float) {
  113. if value.isNaN {
  114. append(staticText: "nan")
  115. } else if !value.isFinite {
  116. if value < 0 {
  117. append(staticText: "-inf")
  118. } else {
  119. append(staticText: "inf")
  120. }
  121. } else {
  122. data.append(contentsOf: value.debugDescription.utf8)
  123. }
  124. }
  125. mutating func putDoubleValue(value: Double) {
  126. if value.isNaN {
  127. append(staticText: "nan")
  128. } else if !value.isFinite {
  129. if value < 0 {
  130. append(staticText: "-inf")
  131. } else {
  132. append(staticText: "inf")
  133. }
  134. } else {
  135. data.append(contentsOf: value.debugDescription.utf8)
  136. }
  137. }
  138. private mutating func appendUInt(value: UInt64) {
  139. if value >= 1000 {
  140. appendUInt(value: value / 1000)
  141. }
  142. if value >= 100 {
  143. data.append(asciiZero + UInt8((value / 100) % 10))
  144. }
  145. if value >= 10 {
  146. data.append(asciiZero + UInt8((value / 10) % 10))
  147. }
  148. data.append(asciiZero + UInt8(value % 10))
  149. }
  150. private mutating func appendInt(value: Int64) {
  151. if value < 0 {
  152. data.append(asciiMinus)
  153. // This is the twos-complement negation of value,
  154. // computed in a way that won't overflow a 64-bit
  155. // signed integer.
  156. appendUInt(value: 1 + ~UInt64(bitPattern: value))
  157. } else {
  158. appendUInt(value: UInt64(bitPattern: value))
  159. }
  160. }
  161. mutating func putInt64(value: Int64) {
  162. appendInt(value: value)
  163. }
  164. mutating func putUInt64(value: UInt64) {
  165. appendUInt(value: value)
  166. }
  167. mutating func appendUIntHex(value: UInt64, digits: Int) {
  168. if digits == 0 {
  169. append(staticText: "0x")
  170. } else {
  171. appendUIntHex(value: value >> 4, digits: digits - 1)
  172. let d = UInt8(truncatingIfNeeded: value % 16)
  173. data.append(d < 10 ? asciiZero + d : asciiUpperA + d - 10)
  174. }
  175. }
  176. mutating func putUInt64Hex(value: UInt64, digits: Int) {
  177. appendUIntHex(value: value, digits: digits)
  178. }
  179. mutating func putBoolValue(value: Bool) {
  180. append(staticText: value ? "true" : "false")
  181. }
  182. mutating func putStringValue(value: String) {
  183. data.append(asciiDoubleQuote)
  184. for c in value.unicodeScalars {
  185. switch c.value {
  186. // Special two-byte escapes
  187. case 8:
  188. append(staticText: "\\b")
  189. case 9:
  190. append(staticText: "\\t")
  191. case 10:
  192. append(staticText: "\\n")
  193. case 11:
  194. append(staticText: "\\v")
  195. case 12:
  196. append(staticText: "\\f")
  197. case 13:
  198. append(staticText: "\\r")
  199. case 34:
  200. append(staticText: "\\\"")
  201. case 92:
  202. append(staticText: "\\\\")
  203. case 0...31, 127: // Octal form for C0 control chars
  204. data.append(asciiBackslash)
  205. data.append(asciiZero + UInt8(c.value / 64))
  206. data.append(asciiZero + UInt8(c.value / 8 % 8))
  207. data.append(asciiZero + UInt8(c.value % 8))
  208. case 0...127: // ASCII
  209. data.append(UInt8(truncatingIfNeeded: c.value))
  210. case 0x80...0x7ff:
  211. data.append(0xc0 + UInt8(c.value / 64))
  212. data.append(0x80 + UInt8(c.value % 64))
  213. case 0x800...0xffff:
  214. data.append(0xe0 + UInt8(truncatingIfNeeded: c.value >> 12))
  215. data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
  216. data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
  217. default:
  218. data.append(0xf0 + UInt8(truncatingIfNeeded: c.value >> 18))
  219. data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 12) & 0x3f))
  220. data.append(0x80 + UInt8(truncatingIfNeeded: (c.value >> 6) & 0x3f))
  221. data.append(0x80 + UInt8(truncatingIfNeeded: c.value & 0x3f))
  222. }
  223. }
  224. data.append(asciiDoubleQuote)
  225. }
  226. mutating func putBytesValue(value: Data) {
  227. data.append(asciiDoubleQuote)
  228. value.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
  229. if let p = body.baseAddress, body.count > 0 {
  230. for i in 0..<body.count {
  231. let c = p[i]
  232. switch c {
  233. // Special two-byte escapes
  234. case 8:
  235. append(staticText: "\\b")
  236. case 9:
  237. append(staticText: "\\t")
  238. case 10:
  239. append(staticText: "\\n")
  240. case 11:
  241. append(staticText: "\\v")
  242. case 12:
  243. append(staticText: "\\f")
  244. case 13:
  245. append(staticText: "\\r")
  246. case 34:
  247. append(staticText: "\\\"")
  248. case 92:
  249. append(staticText: "\\\\")
  250. case 32...126: // printable ASCII
  251. data.append(c)
  252. default: // Octal form for non-printable chars
  253. data.append(asciiBackslash)
  254. data.append(asciiZero + UInt8(c / 64))
  255. data.append(asciiZero + UInt8(c / 8 % 8))
  256. data.append(asciiZero + UInt8(c % 8))
  257. }
  258. }
  259. }
  260. }
  261. data.append(asciiDoubleQuote)
  262. }
  263. }