PQLZStringUtil.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import Foundation
  2. private let keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
  3. private let keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$"
  4. private let getCharFromInt: (Int) -> Character = { a in
  5. if let scalar = Unicode.Scalar(a) {
  6. return Character(scalar)
  7. } else {
  8. return Character(" ")
  9. }
  10. }
  11. private var baseReserveDict = [String: [Character: Int]]()
  12. private typealias GetCharFromInt<T> = (Int) -> T
  13. private typealias GetNextValue = (Int) -> Int
  14. private typealias DecompressData = (value: Int, position: Int, index: Int)
  15. private typealias CompressContext<T> = (dict: [String: Int], dictCreate: [String: Bool], data: T, val: Int, position: Int) where T: RangeReplaceableCollection
  16. private func getBaseValue(alphabet: String, char: Character) -> Int {
  17. if let charcter = baseReserveDict[alphabet]?[char] {
  18. return charcter
  19. } else {
  20. baseReserveDict[alphabet] = [Character: Int]()
  21. for (index, char) in alphabet.enumerated() {
  22. baseReserveDict[alphabet]![char] = index
  23. }
  24. return baseReserveDict[alphabet]![char]!
  25. }
  26. }
  27. public func compressToBase64(input: String) -> String {
  28. guard !input.isEmpty else {
  29. return ""
  30. }
  31. let result = _compress(input: input, bitPerChar: 6, charFromInt: { a in String(keyStrBase64[a]) })
  32. switch result.count % 4 {
  33. case 0:
  34. return result
  35. case 1:
  36. return result + "==="
  37. case 2:
  38. return result + "=="
  39. case 3:
  40. return result + "="
  41. default:
  42. return ""
  43. }
  44. }
  45. public func decompressFromBase64(input: String) -> String {
  46. guard !input.isEmpty else {
  47. return ""
  48. }
  49. return _decompress(length: input.count, resetValue: 32, nextValue: { a in getBaseValue(alphabet: keyStrBase64, char: input[a]) })
  50. }
  51. public func compressToUTF16(input: String) -> String {
  52. guard !input.isEmpty else {
  53. return ""
  54. }
  55. return _compress(input: input, bitPerChar: 15, charFromInt: { a in String(getCharFromInt(a + 32)) }) + " "
  56. }
  57. public func decompressFromUTF16(input: String) -> String {
  58. guard !input.isEmpty else {
  59. return ""
  60. }
  61. return _decompress(length: input.utf16.count, resetValue: 16384, nextValue: { i in Int(input.utf16[i]) - 32 })
  62. }
  63. public func compressToUInt8Array(input: String) -> [UInt8] {
  64. let compressed: Data = compress(input: input)
  65. var buffer = [UInt8](repeating: 0, count: compressed.count)
  66. for i in 0 ..< (compressed.count / 2) {
  67. buffer[i * 2] = compressed[i * 2 + 1]
  68. buffer[i * 2 + 1] = compressed[i * 2]
  69. }
  70. return buffer
  71. }
  72. public func decompressFromUInt8Array(input: [UInt8]) -> String {
  73. guard !input.isEmpty else {
  74. return ""
  75. }
  76. return _decompress(length: input.count / 2, resetValue: 32768, nextValue: { i in
  77. let lower = Int(input[i * 2]) * 256
  78. let upper = Int(input[i * 2 + 1])
  79. return upper + lower
  80. })
  81. }
  82. public func compressToEncodedURIComponent(input: String) -> String {
  83. guard !input.isEmpty else {
  84. return ""
  85. }
  86. return _compress(input: input, bitPerChar: 6, charFromInt: { i in String(keyStrUriSafe[i]) })
  87. }
  88. public func decompressFromEncodedURIComponent(input: String) -> String {
  89. guard !input.isEmpty else {
  90. return ""
  91. }
  92. let replaced = input.replacingOccurrences(of: " ", with: "+")
  93. return _decompress(length: replaced.count, resetValue: 32, nextValue: { a in getBaseValue(alphabet: keyStrUriSafe, char: input[a]) })
  94. }
  95. public func compress(input: String) -> String {
  96. guard !input.isEmpty else {
  97. return ""
  98. }
  99. return _compress(input: input, bitPerChar: 16, charFromInt: { a in String(getCharFromInt(a)) })
  100. }
  101. public func compress(input: String) -> Data {
  102. guard !input.isEmpty else {
  103. return Data()
  104. }
  105. return _compress(input: input, bitPerChar: 16, charFromInt: { a in
  106. Data(bytes: [UInt8(a % 256), UInt8(a >> 8)])
  107. })
  108. }
  109. // TODO: Change Generics
  110. private func _compress<T: RangeReplaceableCollection>(input: String, bitPerChar: Int, charFromInt: GetCharFromInt<T>) -> T {
  111. guard !input.isEmpty else {
  112. return T()
  113. }
  114. var value = 0
  115. var wc = ""
  116. var w = ""
  117. var enlargeIn = 2
  118. var dictSize = 3
  119. var numBits = 2
  120. var context = (dict: [String: Int](), dictCreate: [String: Bool](), data: T(), val: 0, position: 0)
  121. for c in input {
  122. let s = String(c)
  123. if context.dict.index(forKey: s) == nil {
  124. context.dict[s] = dictSize
  125. context.dictCreate[s] = true
  126. dictSize += 1
  127. }
  128. wc = w + s
  129. if context.dict[wc] != nil {
  130. w = wc
  131. } else {
  132. if context.dictCreate.index(forKey: w) != nil {
  133. if let scalar = w.unicodeScalars.first, scalar.value < 256 {
  134. for _ in 0 ..< numBits {
  135. context.val <<= 1
  136. if context.position == bitPerChar - 1 {
  137. context.position = 0
  138. context.data += charFromInt(context.val)
  139. context.val = 0
  140. } else {
  141. context.position += 1
  142. }
  143. }
  144. value = Int(w.unicodeScalars.first!.value)
  145. for _ in 0 ..< 8 {
  146. context.val = (context.val << 1) | (value & 1)
  147. if context.position == bitPerChar - 1 {
  148. context.position = 0
  149. context.data += charFromInt(context.val)
  150. context.val = 0
  151. } else {
  152. context.position += 1
  153. }
  154. value >>= 1
  155. }
  156. } else {
  157. value = 1
  158. for _ in 0 ..< numBits {
  159. context.val = (context.val << 1) | value
  160. if context.position == bitPerChar - 1 {
  161. context.position = 0
  162. context.data += charFromInt(context.val)
  163. context.val = 0
  164. } else {
  165. context.position += 1
  166. }
  167. value = 0
  168. }
  169. value = Int(w.unicodeScalars.first!.value)
  170. for _ in 0 ..< 16 {
  171. context.val = (context.val << 1) | (value & 1)
  172. if context.position == bitPerChar - 1 {
  173. context.position = 0
  174. context.data += charFromInt(context.val)
  175. context.val = 0
  176. } else {
  177. context.position += 1
  178. }
  179. value >>= 1
  180. }
  181. }
  182. enlargeIn -= 1
  183. if enlargeIn == 0 {
  184. enlargeIn = 2 << (numBits - 1)
  185. numBits += 1
  186. }
  187. context.dictCreate.removeValue(forKey: w)
  188. } else {
  189. value = context.dict[w]!
  190. for _ in 0 ..< numBits {
  191. context.val = (context.val << 1) | (value & 1)
  192. if context.position == bitPerChar - 1 {
  193. context.position = 0
  194. context.data += charFromInt(context.val)
  195. context.val = 0
  196. } else {
  197. context.position += 1
  198. }
  199. value >>= 1
  200. }
  201. }
  202. enlargeIn -= 1
  203. if enlargeIn == 0 {
  204. enlargeIn = 2 << (numBits - 1)
  205. numBits += 1
  206. }
  207. context.dict[wc] = dictSize
  208. dictSize += 1
  209. w = s
  210. }
  211. }
  212. if w != "" {
  213. if context.dictCreate.index(forKey: w) != nil {
  214. if let scalar = w.unicodeScalars.first, scalar.value < 256 {
  215. for _ in 0 ..< numBits {
  216. context.val <<= 1
  217. if context.position == bitPerChar - 1 {
  218. context.position = 0
  219. context.data += charFromInt(context.val)
  220. context.val = 0
  221. } else {
  222. context.position += 1
  223. }
  224. }
  225. value = Int(w.unicodeScalars.first!.value)
  226. for _ in 0 ..< 8 {
  227. context.val = (context.val << 1) | (value & 1)
  228. if context.position == bitPerChar - 1 {
  229. context.position = 0
  230. context.data += charFromInt(context.val)
  231. context.val = 0
  232. } else {
  233. context.position += 1
  234. }
  235. value >>= 1
  236. }
  237. } else {
  238. value = 1
  239. for _ in 0 ..< numBits {
  240. context.val = (context.val << 1) | value
  241. if context.position == bitPerChar - 1 {
  242. context.position = 0
  243. context.data += charFromInt(context.val)
  244. context.val = 0
  245. } else {
  246. context.position += 1
  247. }
  248. value = 0
  249. }
  250. value = Int(w.unicodeScalars.first!.value)
  251. for _ in 0 ..< 16 {
  252. context.val = (context.val << 1) | (value & 1)
  253. if context.position == bitPerChar - 1 {
  254. context.position = 0
  255. context.data += charFromInt(context.val)
  256. context.val = 0
  257. } else {
  258. context.position += 1
  259. }
  260. value >>= 1
  261. }
  262. }
  263. enlargeIn -= 1
  264. if enlargeIn == 0 {
  265. enlargeIn = 2 << (numBits - 1)
  266. numBits += 1
  267. }
  268. context.dictCreate.removeValue(forKey: w)
  269. } else {
  270. value = context.dict[w]!
  271. for _ in 0 ..< numBits {
  272. context.val = (context.val << 1) | (value & 1)
  273. if context.position == bitPerChar - 1 {
  274. context.position = 0
  275. context.data += charFromInt(context.val)
  276. context.val = 0
  277. } else {
  278. context.position += 1
  279. }
  280. value >>= 1
  281. }
  282. }
  283. enlargeIn -= 1
  284. if enlargeIn == 0 {
  285. enlargeIn = 2 << (numBits - 1)
  286. numBits += 1
  287. }
  288. }
  289. value = 2
  290. for _ in 0 ..< numBits {
  291. context.val = (context.val << 1) | (value & 1)
  292. if context.position == bitPerChar - 1 {
  293. context.position = 0
  294. context.data += charFromInt(context.val)
  295. context.val = 0
  296. } else {
  297. context.position += 1
  298. }
  299. value >>= 1
  300. }
  301. while true {
  302. context.val <<= 1
  303. if context.position == bitPerChar - 1 {
  304. context.data += charFromInt(context.val)
  305. break
  306. } else {
  307. context.position += 1
  308. }
  309. }
  310. return context.data
  311. }
  312. public func decompress(input: String) -> String {
  313. guard !input.isEmpty else {
  314. return ""
  315. }
  316. return _decompress(length: input.utf16.count, resetValue: 32768, nextValue: { i in Int(input.utf16[i]) })
  317. }
  318. public func decompress(input: Data) -> String {
  319. guard !input.isEmpty else {
  320. return ""
  321. }
  322. return _decompress(length: input.count / 2, resetValue: 32768, nextValue: { i in
  323. let lower = Int(input[i * 2])
  324. let upper = Int(input[i * 2 + 1]) * 256
  325. return upper + lower
  326. })
  327. }
  328. private func _decompress(length: Int, resetValue: Int, nextValue: @escaping GetNextValue) -> String {
  329. var dict: [Int: String] = [0: "\u{0}", 1: "\u{1}", 2: "\u{2}"]
  330. var next = 0
  331. var enlargeIn = 4
  332. var dictSize = 4
  333. var numBits = 3
  334. var bits = 0
  335. var c = 0
  336. var entry = ""
  337. var w = ""
  338. var result = ""
  339. var data = (value: nextValue(0), position: resetValue, index: 1)
  340. func _slide(data: inout DecompressData, maxpower: Int) -> Int {
  341. var bits = 0
  342. var power = 1
  343. while power != maxpower {
  344. let resb = data.value & data.position
  345. data.position >>= 1
  346. if data.position == 0 {
  347. data.position = resetValue
  348. data.value = nextValue(data.index)
  349. data.index += 1
  350. }
  351. bits |= (resb > 0 ? 1 : 0) * power
  352. power <<= 1
  353. }
  354. return bits
  355. }
  356. bits = _slide(data: &data, maxpower: 2 << 1)
  357. next = bits
  358. if next == 0 {
  359. bits = _slide(data: &data, maxpower: 2 << 7)
  360. c = bits
  361. } else if next == 1 {
  362. bits = _slide(data: &data, maxpower: 2 << 15)
  363. c = bits
  364. } else if next == 2 {
  365. return ""
  366. }
  367. w = String(Unicode.Scalar(c)!)
  368. dict[3] = w
  369. result += w
  370. while true {
  371. guard data.index <= length else {
  372. return ""
  373. }
  374. bits = _slide(data: &data, maxpower: 2 << (numBits - 1))
  375. c = bits
  376. if c == 0 {
  377. bits = _slide(data: &data, maxpower: 2 << 7)
  378. dict[dictSize] = String(getCharFromInt(bits))
  379. dictSize += 1
  380. c = dictSize - 1
  381. enlargeIn -= 1
  382. } else if c == 1 {
  383. bits = _slide(data: &data, maxpower: 2 << 15)
  384. dict[dictSize] = String(getCharFromInt(bits))
  385. dictSize += 1
  386. c = dictSize - 1
  387. enlargeIn -= 1
  388. } else if c == 2 {
  389. return result
  390. }
  391. if enlargeIn == 0 {
  392. enlargeIn = 2 << (numBits - 1)
  393. numBits += 1
  394. }
  395. if let e = dict[c] {
  396. entry = e
  397. } else {
  398. if c == dictSize {
  399. entry = w + String(w[0])
  400. } else {
  401. return ""
  402. }
  403. }
  404. result += entry
  405. dict[dictSize] = w + String(entry[0])
  406. dictSize += 1
  407. enlargeIn -= 1
  408. w = entry
  409. if enlargeIn == 0 {
  410. enlargeIn = 2 << (numBits - 1)
  411. numBits += 1
  412. }
  413. }
  414. }
  415. extension String {
  416. subscript(pos: Int) -> Character {
  417. return self[String.Index(encodedOffset: pos)]
  418. }
  419. }
  420. extension String.UTF16View {
  421. subscript(pos: Int) -> Unicode.UTF16.CodeUnit {
  422. return self[String.UTF16View.Index(encodedOffset: pos)]
  423. }
  424. }