gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
  127. 127
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133
  134. 134
package brotli

/* Copyright 2013 Google Inc. All Rights Reserved.

   Distributed under MIT license.
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/

/* A ringBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
   data in a circular manner: writing a byte writes it to:
     `position() % (1 << window_bits)'.
   For convenience, the ringBuffer array contains another copy of the
   first `1 << tail_bits' bytes:
     buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
   and another copy of the last two bytes:
     buffer_[-1] == buffer_[(1 << window_bits) - 1] and
     buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
type ringBuffer struct {
	size_       uint32
	mask_       uint32
	tail_size_  uint32
	total_size_ uint32
	cur_size_   uint32
	pos_        uint32
	data_       []byte
	buffer_     []byte
}

func ringBufferInit(rb *ringBuffer) {
	rb.pos_ = 0
}

func ringBufferSetup(params *encoderParams, rb *ringBuffer) {
	var window_bits int = computeRbBits(params)
	var tail_bits int = params.lgblock
	*(*uint32)(&rb.size_) = 1 << uint(window_bits)
	*(*uint32)(&rb.mask_) = (1 << uint(window_bits)) - 1
	*(*uint32)(&rb.tail_size_) = 1 << uint(tail_bits)
	*(*uint32)(&rb.total_size_) = rb.size_ + rb.tail_size_
}

const kSlackForEightByteHashingEverywhere uint = 7

/* Allocates or re-allocates data_ to the given length + plus some slack
   region before and after. Fills the slack regions with zeros. */
func ringBufferInitBuffer(buflen uint32, rb *ringBuffer) {
	var new_data []byte
	var i uint
	size := 2 + int(buflen) + int(kSlackForEightByteHashingEverywhere)
	if cap(rb.data_) < size {
		new_data = make([]byte, size)
	} else {
		new_data = rb.data_[:size]
	}
	if rb.data_ != nil {
		copy(new_data, rb.data_[:2+rb.cur_size_+uint32(kSlackForEightByteHashingEverywhere)])
	}

	rb.data_ = new_data
	rb.cur_size_ = buflen
	rb.buffer_ = rb.data_[2:]
	rb.data_[1] = 0
	rb.data_[0] = rb.data_[1]
	for i = 0; i < kSlackForEightByteHashingEverywhere; i++ {
		rb.buffer_[rb.cur_size_+uint32(i)] = 0
	}
}

func ringBufferWriteTail(bytes []byte, n uint, rb *ringBuffer) {
	var masked_pos uint = uint(rb.pos_ & rb.mask_)
	if uint32(masked_pos) < rb.tail_size_ {
		/* Just fill the tail buffer with the beginning data. */
		var p uint = uint(rb.size_ + uint32(masked_pos))
		copy(rb.buffer_[p:], bytes[:brotli_min_size_t(n, uint(rb.tail_size_-uint32(masked_pos)))])
	}
}

/* Push bytes into the ring buffer. */
func ringBufferWrite(bytes []byte, n uint, rb *ringBuffer) {
	if rb.pos_ == 0 && uint32(n) < rb.tail_size_ {
		/* Special case for the first write: to process the first block, we don't
		   need to allocate the whole ring-buffer and we don't need the tail
		   either. However, we do this memory usage optimization only if the
		   first write is less than the tail size, which is also the input block
		   size, otherwise it is likely that other blocks will follow and we
		   will need to reallocate to the full size anyway. */
		rb.pos_ = uint32(n)

		ringBufferInitBuffer(rb.pos_, rb)
		copy(rb.buffer_, bytes[:n])
		return
	}

	if rb.cur_size_ < rb.total_size_ {
		/* Lazily allocate the full buffer. */
		ringBufferInitBuffer(rb.total_size_, rb)

		/* Initialize the last two bytes to zero, so that we don't have to worry
		   later when we copy the last two bytes to the first two positions. */
		rb.buffer_[rb.size_-2] = 0

		rb.buffer_[rb.size_-1] = 0
	}
	{
		var masked_pos uint = uint(rb.pos_ & rb.mask_)

		/* The length of the writes is limited so that we do not need to worry
		   about a write */
		ringBufferWriteTail(bytes, n, rb)

		if uint32(masked_pos+n) <= rb.size_ {
			/* A single write fits. */
			copy(rb.buffer_[masked_pos:], bytes[:n])
		} else {
			/* Split into two writes.
			   Copy into the end of the buffer, including the tail buffer. */
			copy(rb.buffer_[masked_pos:], bytes[:brotli_min_size_t(n, uint(rb.total_size_-uint32(masked_pos)))])

			/* Copy into the beginning of the buffer */
			copy(rb.buffer_, bytes[rb.size_-uint32(masked_pos):][:uint32(n)-(rb.size_-uint32(masked_pos))])
		}
	}
	{
		var not_first_lap bool = rb.pos_&(1<<31) != 0
		var rb_pos_mask uint32 = (1 << 31) - 1
		rb.data_[0] = rb.buffer_[rb.size_-2]
		rb.data_[1] = rb.buffer_[rb.size_-1]
		rb.pos_ = (rb.pos_ & rb_pos_mask) + uint32(uint32(n)&rb_pos_mask)
		if not_first_lap {
			/* Wrap, but preserve not-a-first-lap feature. */
			rb.pos_ |= 1 << 31
		}
	}
}