static_dict.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. package brotli
  2. import "encoding/binary"
  3. /* Copyright 2013 Google Inc. All Rights Reserved.
  4. Distributed under MIT license.
  5. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  6. */
  7. /* Class to model the static dictionary. */
  8. const maxStaticDictionaryMatchLen = 37
  9. const kInvalidMatch uint32 = 0xFFFFFFF
  10. /* Copyright 2013 Google Inc. All Rights Reserved.
  11. Distributed under MIT license.
  12. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  13. */
  14. func hash(data []byte) uint32 {
  15. var h uint32 = binary.LittleEndian.Uint32(data) * kDictHashMul32
  16. /* The higher bits contain more mixture from the multiplication,
  17. so we take our results from there. */
  18. return h >> uint(32-kDictNumBits)
  19. }
  20. func addMatch(distance uint, len uint, len_code uint, matches []uint32) {
  21. var match uint32 = uint32((distance << 5) + len_code)
  22. matches[len] = brotli_min_uint32_t(matches[len], match)
  23. }
  24. func dictMatchLength(dict *dictionary, data []byte, id uint, len uint, maxlen uint) uint {
  25. var offset uint = uint(dict.offsets_by_length[len]) + len*id
  26. return findMatchLengthWithLimit(dict.data[offset:], data, brotli_min_size_t(uint(len), maxlen))
  27. }
  28. func isMatch(d *dictionary, w dictWord, data []byte, max_length uint) bool {
  29. if uint(w.len) > max_length {
  30. return false
  31. } else {
  32. var offset uint = uint(d.offsets_by_length[w.len]) + uint(w.len)*uint(w.idx)
  33. var dict []byte = d.data[offset:]
  34. if w.transform == 0 {
  35. /* Match against base dictionary word. */
  36. return findMatchLengthWithLimit(dict, data, uint(w.len)) == uint(w.len)
  37. } else if w.transform == 10 {
  38. /* Match against uppercase first transform.
  39. Note that there are only ASCII uppercase words in the lookup table. */
  40. return dict[0] >= 'a' && dict[0] <= 'z' && (dict[0]^32) == data[0] && findMatchLengthWithLimit(dict[1:], data[1:], uint(w.len)-1) == uint(w.len-1)
  41. } else {
  42. /* Match against uppercase all transform.
  43. Note that there are only ASCII uppercase words in the lookup table. */
  44. var i uint
  45. for i = 0; i < uint(w.len); i++ {
  46. if dict[i] >= 'a' && dict[i] <= 'z' {
  47. if (dict[i] ^ 32) != data[i] {
  48. return false
  49. }
  50. } else {
  51. if dict[i] != data[i] {
  52. return false
  53. }
  54. }
  55. }
  56. return true
  57. }
  58. }
  59. }
  60. func findAllStaticDictionaryMatches(dict *encoderDictionary, data []byte, min_length uint, max_length uint, matches []uint32) bool {
  61. var has_found_match bool = false
  62. {
  63. var offset uint = uint(dict.buckets[hash(data)])
  64. var end bool = offset == 0
  65. for !end {
  66. w := dict.dict_words[offset]
  67. offset++
  68. var l uint = uint(w.len) & 0x1F
  69. var n uint = uint(1) << dict.words.size_bits_by_length[l]
  70. var id uint = uint(w.idx)
  71. end = !(w.len&0x80 == 0)
  72. w.len = byte(l)
  73. if w.transform == 0 {
  74. var matchlen uint = dictMatchLength(dict.words, data, id, l, max_length)
  75. var s []byte
  76. var minlen uint
  77. var maxlen uint
  78. var len uint
  79. /* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */
  80. if matchlen == l {
  81. addMatch(id, l, l, matches)
  82. has_found_match = true
  83. }
  84. /* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and
  85. "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */
  86. if matchlen >= l-1 {
  87. addMatch(id+12*n, l-1, l, matches)
  88. if l+2 < max_length && data[l-1] == 'i' && data[l] == 'n' && data[l+1] == 'g' && data[l+2] == ' ' {
  89. addMatch(id+49*n, l+3, l, matches)
  90. }
  91. has_found_match = true
  92. }
  93. /* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */
  94. minlen = min_length
  95. if l > 9 {
  96. minlen = brotli_max_size_t(minlen, l-9)
  97. }
  98. maxlen = brotli_min_size_t(matchlen, l-2)
  99. for len = minlen; len <= maxlen; len++ {
  100. var cut uint = l - len
  101. var transform_id uint = (cut << 2) + uint((dict.cutoffTransforms>>(cut*6))&0x3F)
  102. addMatch(id+transform_id*n, uint(len), l, matches)
  103. has_found_match = true
  104. }
  105. if matchlen < l || l+6 >= max_length {
  106. continue
  107. }
  108. s = data[l:]
  109. /* Transforms "" + BROTLI_TRANSFORM_IDENTITY + <suffix> */
  110. if s[0] == ' ' {
  111. addMatch(id+n, l+1, l, matches)
  112. if s[1] == 'a' {
  113. if s[2] == ' ' {
  114. addMatch(id+28*n, l+3, l, matches)
  115. } else if s[2] == 's' {
  116. if s[3] == ' ' {
  117. addMatch(id+46*n, l+4, l, matches)
  118. }
  119. } else if s[2] == 't' {
  120. if s[3] == ' ' {
  121. addMatch(id+60*n, l+4, l, matches)
  122. }
  123. } else if s[2] == 'n' {
  124. if s[3] == 'd' && s[4] == ' ' {
  125. addMatch(id+10*n, l+5, l, matches)
  126. }
  127. }
  128. } else if s[1] == 'b' {
  129. if s[2] == 'y' && s[3] == ' ' {
  130. addMatch(id+38*n, l+4, l, matches)
  131. }
  132. } else if s[1] == 'i' {
  133. if s[2] == 'n' {
  134. if s[3] == ' ' {
  135. addMatch(id+16*n, l+4, l, matches)
  136. }
  137. } else if s[2] == 's' {
  138. if s[3] == ' ' {
  139. addMatch(id+47*n, l+4, l, matches)
  140. }
  141. }
  142. } else if s[1] == 'f' {
  143. if s[2] == 'o' {
  144. if s[3] == 'r' && s[4] == ' ' {
  145. addMatch(id+25*n, l+5, l, matches)
  146. }
  147. } else if s[2] == 'r' {
  148. if s[3] == 'o' && s[4] == 'm' && s[5] == ' ' {
  149. addMatch(id+37*n, l+6, l, matches)
  150. }
  151. }
  152. } else if s[1] == 'o' {
  153. if s[2] == 'f' {
  154. if s[3] == ' ' {
  155. addMatch(id+8*n, l+4, l, matches)
  156. }
  157. } else if s[2] == 'n' {
  158. if s[3] == ' ' {
  159. addMatch(id+45*n, l+4, l, matches)
  160. }
  161. }
  162. } else if s[1] == 'n' {
  163. if s[2] == 'o' && s[3] == 't' && s[4] == ' ' {
  164. addMatch(id+80*n, l+5, l, matches)
  165. }
  166. } else if s[1] == 't' {
  167. if s[2] == 'h' {
  168. if s[3] == 'e' {
  169. if s[4] == ' ' {
  170. addMatch(id+5*n, l+5, l, matches)
  171. }
  172. } else if s[3] == 'a' {
  173. if s[4] == 't' && s[5] == ' ' {
  174. addMatch(id+29*n, l+6, l, matches)
  175. }
  176. }
  177. } else if s[2] == 'o' {
  178. if s[3] == ' ' {
  179. addMatch(id+17*n, l+4, l, matches)
  180. }
  181. }
  182. } else if s[1] == 'w' {
  183. if s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ' {
  184. addMatch(id+35*n, l+6, l, matches)
  185. }
  186. }
  187. } else if s[0] == '"' {
  188. addMatch(id+19*n, l+1, l, matches)
  189. if s[1] == '>' {
  190. addMatch(id+21*n, l+2, l, matches)
  191. }
  192. } else if s[0] == '.' {
  193. addMatch(id+20*n, l+1, l, matches)
  194. if s[1] == ' ' {
  195. addMatch(id+31*n, l+2, l, matches)
  196. if s[2] == 'T' && s[3] == 'h' {
  197. if s[4] == 'e' {
  198. if s[5] == ' ' {
  199. addMatch(id+43*n, l+6, l, matches)
  200. }
  201. } else if s[4] == 'i' {
  202. if s[5] == 's' && s[6] == ' ' {
  203. addMatch(id+75*n, l+7, l, matches)
  204. }
  205. }
  206. }
  207. }
  208. } else if s[0] == ',' {
  209. addMatch(id+76*n, l+1, l, matches)
  210. if s[1] == ' ' {
  211. addMatch(id+14*n, l+2, l, matches)
  212. }
  213. } else if s[0] == '\n' {
  214. addMatch(id+22*n, l+1, l, matches)
  215. if s[1] == '\t' {
  216. addMatch(id+50*n, l+2, l, matches)
  217. }
  218. } else if s[0] == ']' {
  219. addMatch(id+24*n, l+1, l, matches)
  220. } else if s[0] == '\'' {
  221. addMatch(id+36*n, l+1, l, matches)
  222. } else if s[0] == ':' {
  223. addMatch(id+51*n, l+1, l, matches)
  224. } else if s[0] == '(' {
  225. addMatch(id+57*n, l+1, l, matches)
  226. } else if s[0] == '=' {
  227. if s[1] == '"' {
  228. addMatch(id+70*n, l+2, l, matches)
  229. } else if s[1] == '\'' {
  230. addMatch(id+86*n, l+2, l, matches)
  231. }
  232. } else if s[0] == 'a' {
  233. if s[1] == 'l' && s[2] == ' ' {
  234. addMatch(id+84*n, l+3, l, matches)
  235. }
  236. } else if s[0] == 'e' {
  237. if s[1] == 'd' {
  238. if s[2] == ' ' {
  239. addMatch(id+53*n, l+3, l, matches)
  240. }
  241. } else if s[1] == 'r' {
  242. if s[2] == ' ' {
  243. addMatch(id+82*n, l+3, l, matches)
  244. }
  245. } else if s[1] == 's' {
  246. if s[2] == 't' && s[3] == ' ' {
  247. addMatch(id+95*n, l+4, l, matches)
  248. }
  249. }
  250. } else if s[0] == 'f' {
  251. if s[1] == 'u' && s[2] == 'l' && s[3] == ' ' {
  252. addMatch(id+90*n, l+4, l, matches)
  253. }
  254. } else if s[0] == 'i' {
  255. if s[1] == 'v' {
  256. if s[2] == 'e' && s[3] == ' ' {
  257. addMatch(id+92*n, l+4, l, matches)
  258. }
  259. } else if s[1] == 'z' {
  260. if s[2] == 'e' && s[3] == ' ' {
  261. addMatch(id+100*n, l+4, l, matches)
  262. }
  263. }
  264. } else if s[0] == 'l' {
  265. if s[1] == 'e' {
  266. if s[2] == 's' && s[3] == 's' && s[4] == ' ' {
  267. addMatch(id+93*n, l+5, l, matches)
  268. }
  269. } else if s[1] == 'y' {
  270. if s[2] == ' ' {
  271. addMatch(id+61*n, l+3, l, matches)
  272. }
  273. }
  274. } else if s[0] == 'o' {
  275. if s[1] == 'u' && s[2] == 's' && s[3] == ' ' {
  276. addMatch(id+106*n, l+4, l, matches)
  277. }
  278. }
  279. } else {
  280. var is_all_caps bool = (w.transform != transformUppercaseFirst)
  281. /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
  282. is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
  283. transform. */
  284. var s []byte
  285. if !isMatch(dict.words, w, data, max_length) {
  286. continue
  287. }
  288. /* Transform "" + kUppercase{First,All} + "" */
  289. var tmp int
  290. if is_all_caps {
  291. tmp = 44
  292. } else {
  293. tmp = 9
  294. }
  295. addMatch(id+uint(tmp)*n, l, l, matches)
  296. has_found_match = true
  297. if l+1 >= max_length {
  298. continue
  299. }
  300. /* Transforms "" + kUppercase{First,All} + <suffix> */
  301. s = data[l:]
  302. if s[0] == ' ' {
  303. var tmp int
  304. if is_all_caps {
  305. tmp = 68
  306. } else {
  307. tmp = 4
  308. }
  309. addMatch(id+uint(tmp)*n, l+1, l, matches)
  310. } else if s[0] == '"' {
  311. var tmp int
  312. if is_all_caps {
  313. tmp = 87
  314. } else {
  315. tmp = 66
  316. }
  317. addMatch(id+uint(tmp)*n, l+1, l, matches)
  318. if s[1] == '>' {
  319. var tmp int
  320. if is_all_caps {
  321. tmp = 97
  322. } else {
  323. tmp = 69
  324. }
  325. addMatch(id+uint(tmp)*n, l+2, l, matches)
  326. }
  327. } else if s[0] == '.' {
  328. var tmp int
  329. if is_all_caps {
  330. tmp = 101
  331. } else {
  332. tmp = 79
  333. }
  334. addMatch(id+uint(tmp)*n, l+1, l, matches)
  335. if s[1] == ' ' {
  336. var tmp int
  337. if is_all_caps {
  338. tmp = 114
  339. } else {
  340. tmp = 88
  341. }
  342. addMatch(id+uint(tmp)*n, l+2, l, matches)
  343. }
  344. } else if s[0] == ',' {
  345. var tmp int
  346. if is_all_caps {
  347. tmp = 112
  348. } else {
  349. tmp = 99
  350. }
  351. addMatch(id+uint(tmp)*n, l+1, l, matches)
  352. if s[1] == ' ' {
  353. var tmp int
  354. if is_all_caps {
  355. tmp = 107
  356. } else {
  357. tmp = 58
  358. }
  359. addMatch(id+uint(tmp)*n, l+2, l, matches)
  360. }
  361. } else if s[0] == '\'' {
  362. var tmp int
  363. if is_all_caps {
  364. tmp = 94
  365. } else {
  366. tmp = 74
  367. }
  368. addMatch(id+uint(tmp)*n, l+1, l, matches)
  369. } else if s[0] == '(' {
  370. var tmp int
  371. if is_all_caps {
  372. tmp = 113
  373. } else {
  374. tmp = 78
  375. }
  376. addMatch(id+uint(tmp)*n, l+1, l, matches)
  377. } else if s[0] == '=' {
  378. if s[1] == '"' {
  379. var tmp int
  380. if is_all_caps {
  381. tmp = 105
  382. } else {
  383. tmp = 104
  384. }
  385. addMatch(id+uint(tmp)*n, l+2, l, matches)
  386. } else if s[1] == '\'' {
  387. var tmp int
  388. if is_all_caps {
  389. tmp = 116
  390. } else {
  391. tmp = 108
  392. }
  393. addMatch(id+uint(tmp)*n, l+2, l, matches)
  394. }
  395. }
  396. }
  397. }
  398. }
  399. /* Transforms with prefixes " " and "." */
  400. if max_length >= 5 && (data[0] == ' ' || data[0] == '.') {
  401. var is_space bool = (data[0] == ' ')
  402. var offset uint = uint(dict.buckets[hash(data[1:])])
  403. var end bool = offset == 0
  404. for !end {
  405. w := dict.dict_words[offset]
  406. offset++
  407. var l uint = uint(w.len) & 0x1F
  408. var n uint = uint(1) << dict.words.size_bits_by_length[l]
  409. var id uint = uint(w.idx)
  410. end = !(w.len&0x80 == 0)
  411. w.len = byte(l)
  412. if w.transform == 0 {
  413. var s []byte
  414. if !isMatch(dict.words, w, data[1:], max_length-1) {
  415. continue
  416. }
  417. /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and
  418. "." + BROTLI_TRANSFORM_IDENTITY + "" */
  419. var tmp int
  420. if is_space {
  421. tmp = 6
  422. } else {
  423. tmp = 32
  424. }
  425. addMatch(id+uint(tmp)*n, l+1, l, matches)
  426. has_found_match = true
  427. if l+2 >= max_length {
  428. continue
  429. }
  430. /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + <suffix> and
  431. "." + BROTLI_TRANSFORM_IDENTITY + <suffix>
  432. */
  433. s = data[l+1:]
  434. if s[0] == ' ' {
  435. var tmp int
  436. if is_space {
  437. tmp = 2
  438. } else {
  439. tmp = 77
  440. }
  441. addMatch(id+uint(tmp)*n, l+2, l, matches)
  442. } else if s[0] == '(' {
  443. var tmp int
  444. if is_space {
  445. tmp = 89
  446. } else {
  447. tmp = 67
  448. }
  449. addMatch(id+uint(tmp)*n, l+2, l, matches)
  450. } else if is_space {
  451. if s[0] == ',' {
  452. addMatch(id+103*n, l+2, l, matches)
  453. if s[1] == ' ' {
  454. addMatch(id+33*n, l+3, l, matches)
  455. }
  456. } else if s[0] == '.' {
  457. addMatch(id+71*n, l+2, l, matches)
  458. if s[1] == ' ' {
  459. addMatch(id+52*n, l+3, l, matches)
  460. }
  461. } else if s[0] == '=' {
  462. if s[1] == '"' {
  463. addMatch(id+81*n, l+3, l, matches)
  464. } else if s[1] == '\'' {
  465. addMatch(id+98*n, l+3, l, matches)
  466. }
  467. }
  468. }
  469. } else if is_space {
  470. var is_all_caps bool = (w.transform != transformUppercaseFirst)
  471. /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and
  472. is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)
  473. transform. */
  474. var s []byte
  475. if !isMatch(dict.words, w, data[1:], max_length-1) {
  476. continue
  477. }
  478. /* Transforms " " + kUppercase{First,All} + "" */
  479. var tmp int
  480. if is_all_caps {
  481. tmp = 85
  482. } else {
  483. tmp = 30
  484. }
  485. addMatch(id+uint(tmp)*n, l+1, l, matches)
  486. has_found_match = true
  487. if l+2 >= max_length {
  488. continue
  489. }
  490. /* Transforms " " + kUppercase{First,All} + <suffix> */
  491. s = data[l+1:]
  492. if s[0] == ' ' {
  493. var tmp int
  494. if is_all_caps {
  495. tmp = 83
  496. } else {
  497. tmp = 15
  498. }
  499. addMatch(id+uint(tmp)*n, l+2, l, matches)
  500. } else if s[0] == ',' {
  501. if !is_all_caps {
  502. addMatch(id+109*n, l+2, l, matches)
  503. }
  504. if s[1] == ' ' {
  505. var tmp int
  506. if is_all_caps {
  507. tmp = 111
  508. } else {
  509. tmp = 65
  510. }
  511. addMatch(id+uint(tmp)*n, l+3, l, matches)
  512. }
  513. } else if s[0] == '.' {
  514. var tmp int
  515. if is_all_caps {
  516. tmp = 115
  517. } else {
  518. tmp = 96
  519. }
  520. addMatch(id+uint(tmp)*n, l+2, l, matches)
  521. if s[1] == ' ' {
  522. var tmp int
  523. if is_all_caps {
  524. tmp = 117
  525. } else {
  526. tmp = 91
  527. }
  528. addMatch(id+uint(tmp)*n, l+3, l, matches)
  529. }
  530. } else if s[0] == '=' {
  531. if s[1] == '"' {
  532. var tmp int
  533. if is_all_caps {
  534. tmp = 110
  535. } else {
  536. tmp = 118
  537. }
  538. addMatch(id+uint(tmp)*n, l+3, l, matches)
  539. } else if s[1] == '\'' {
  540. var tmp int
  541. if is_all_caps {
  542. tmp = 119
  543. } else {
  544. tmp = 120
  545. }
  546. addMatch(id+uint(tmp)*n, l+3, l, matches)
  547. }
  548. }
  549. }
  550. }
  551. }
  552. if max_length >= 6 {
  553. /* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */
  554. if (data[1] == ' ' && (data[0] == 'e' || data[0] == 's' || data[0] == ',')) || (data[0] == 0xC2 && data[1] == 0xA0) {
  555. var offset uint = uint(dict.buckets[hash(data[2:])])
  556. var end bool = offset == 0
  557. for !end {
  558. w := dict.dict_words[offset]
  559. offset++
  560. var l uint = uint(w.len) & 0x1F
  561. var n uint = uint(1) << dict.words.size_bits_by_length[l]
  562. var id uint = uint(w.idx)
  563. end = !(w.len&0x80 == 0)
  564. w.len = byte(l)
  565. if w.transform == 0 && isMatch(dict.words, w, data[2:], max_length-2) {
  566. if data[0] == 0xC2 {
  567. addMatch(id+102*n, l+2, l, matches)
  568. has_found_match = true
  569. } else if l+2 < max_length && data[l+2] == ' ' {
  570. var t uint = 13
  571. if data[0] == 'e' {
  572. t = 18
  573. } else if data[0] == 's' {
  574. t = 7
  575. }
  576. addMatch(id+t*n, l+3, l, matches)
  577. has_found_match = true
  578. }
  579. }
  580. }
  581. }
  582. }
  583. if max_length >= 9 {
  584. /* Transforms with prefixes " the " and ".com/" */
  585. if (data[0] == ' ' && data[1] == 't' && data[2] == 'h' && data[3] == 'e' && data[4] == ' ') || (data[0] == '.' && data[1] == 'c' && data[2] == 'o' && data[3] == 'm' && data[4] == '/') {
  586. var offset uint = uint(dict.buckets[hash(data[5:])])
  587. var end bool = offset == 0
  588. for !end {
  589. w := dict.dict_words[offset]
  590. offset++
  591. var l uint = uint(w.len) & 0x1F
  592. var n uint = uint(1) << dict.words.size_bits_by_length[l]
  593. var id uint = uint(w.idx)
  594. end = !(w.len&0x80 == 0)
  595. w.len = byte(l)
  596. if w.transform == 0 && isMatch(dict.words, w, data[5:], max_length-5) {
  597. var tmp int
  598. if data[0] == ' ' {
  599. tmp = 41
  600. } else {
  601. tmp = 72
  602. }
  603. addMatch(id+uint(tmp)*n, l+5, l, matches)
  604. has_found_match = true
  605. if l+5 < max_length {
  606. var s []byte = data[l+5:]
  607. if data[0] == ' ' {
  608. if l+8 < max_length && s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ' {
  609. addMatch(id+62*n, l+9, l, matches)
  610. if l+12 < max_length && s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ' {
  611. addMatch(id+73*n, l+13, l, matches)
  612. }
  613. }
  614. }
  615. }
  616. }
  617. }
  618. }
  619. }
  620. return has_found_match
  621. }