header.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package lzma
  5. import (
  6. "errors"
  7. "fmt"
  8. )
  9. // uint32LE reads an uint32 integer from a byte slice
  10. func uint32LE(b []byte) uint32 {
  11. x := uint32(b[3]) << 24
  12. x |= uint32(b[2]) << 16
  13. x |= uint32(b[1]) << 8
  14. x |= uint32(b[0])
  15. return x
  16. }
  17. // uint64LE converts the uint64 value stored as little endian to an uint64
  18. // value.
  19. func uint64LE(b []byte) uint64 {
  20. x := uint64(b[7]) << 56
  21. x |= uint64(b[6]) << 48
  22. x |= uint64(b[5]) << 40
  23. x |= uint64(b[4]) << 32
  24. x |= uint64(b[3]) << 24
  25. x |= uint64(b[2]) << 16
  26. x |= uint64(b[1]) << 8
  27. x |= uint64(b[0])
  28. return x
  29. }
  30. // putUint32LE puts an uint32 integer into a byte slice that must have at least
  31. // a length of 4 bytes.
  32. func putUint32LE(b []byte, x uint32) {
  33. b[0] = byte(x)
  34. b[1] = byte(x >> 8)
  35. b[2] = byte(x >> 16)
  36. b[3] = byte(x >> 24)
  37. }
  38. // putUint64LE puts the uint64 value into the byte slice as little endian
  39. // value. The byte slice b must have at least place for 8 bytes.
  40. func putUint64LE(b []byte, x uint64) {
  41. b[0] = byte(x)
  42. b[1] = byte(x >> 8)
  43. b[2] = byte(x >> 16)
  44. b[3] = byte(x >> 24)
  45. b[4] = byte(x >> 32)
  46. b[5] = byte(x >> 40)
  47. b[6] = byte(x >> 48)
  48. b[7] = byte(x >> 56)
  49. }
  50. // noHeaderSize defines the value of the length field in the LZMA header.
  51. const noHeaderSize uint64 = 1<<64 - 1
  52. // HeaderLen provides the length of the LZMA file header.
  53. const HeaderLen = 13
  54. // header represents the header of an LZMA file.
  55. type header struct {
  56. properties Properties
  57. dictCap int
  58. // uncompressed size; negative value if no size is given
  59. size int64
  60. }
  61. // marshalBinary marshals the header.
  62. func (h *header) marshalBinary() (data []byte, err error) {
  63. if err = h.properties.verify(); err != nil {
  64. return nil, err
  65. }
  66. if !(0 <= h.dictCap && int64(h.dictCap) <= MaxDictCap) {
  67. return nil, fmt.Errorf("lzma: DictCap %d out of range",
  68. h.dictCap)
  69. }
  70. data = make([]byte, 13)
  71. // property byte
  72. data[0] = h.properties.Code()
  73. // dictionary capacity
  74. putUint32LE(data[1:5], uint32(h.dictCap))
  75. // uncompressed size
  76. var s uint64
  77. if h.size > 0 {
  78. s = uint64(h.size)
  79. } else {
  80. s = noHeaderSize
  81. }
  82. putUint64LE(data[5:], s)
  83. return data, nil
  84. }
  85. // unmarshalBinary unmarshals the header.
  86. func (h *header) unmarshalBinary(data []byte) error {
  87. if len(data) != HeaderLen {
  88. return errors.New("lzma.unmarshalBinary: data has wrong length")
  89. }
  90. // properties
  91. var err error
  92. if h.properties, err = PropertiesForCode(data[0]); err != nil {
  93. return err
  94. }
  95. // dictionary capacity
  96. h.dictCap = int(uint32LE(data[1:]))
  97. if h.dictCap < 0 {
  98. return errors.New(
  99. "LZMA header: dictionary capacity exceeds maximum " +
  100. "integer")
  101. }
  102. // uncompressed size
  103. s := uint64LE(data[5:])
  104. if s == noHeaderSize {
  105. h.size = -1
  106. } else {
  107. h.size = int64(s)
  108. if h.size < 0 {
  109. return errors.New(
  110. "LZMA header: uncompressed size " +
  111. "out of int64 range")
  112. }
  113. }
  114. return nil
  115. }
  116. // validDictCap checks whether the dictionary capacity is correct. This
  117. // is used to weed out wrong file headers.
  118. func validDictCap(dictcap int) bool {
  119. if int64(dictcap) == MaxDictCap {
  120. return true
  121. }
  122. for n := uint(10); n < 32; n++ {
  123. if dictcap == 1<<n {
  124. return true
  125. }
  126. if dictcap == 1<<n+1<<(n-1) {
  127. return true
  128. }
  129. }
  130. return false
  131. }
  132. // ValidHeader checks for a valid LZMA file header. It allows only
  133. // dictionary sizes of 2^n or 2^n+2^(n-1) with n >= 10 or 2^32-1. If
  134. // there is an explicit size it must not exceed 256 GiB. The length of
  135. // the data argument must be HeaderLen.
  136. func ValidHeader(data []byte) bool {
  137. var h header
  138. if err := h.unmarshalBinary(data); err != nil {
  139. return false
  140. }
  141. if !validDictCap(h.dictCap) {
  142. return false
  143. }
  144. return h.size < 0 || h.size <= 1<<38
  145. }