Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

121 строка
3.4 KiB

  1. // Copyright (c) 2017, Google Inc.
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  10. // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  12. // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  13. // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
  14. // ar.go contains functions for parsing .a archive files.
  15. package main
  16. import (
  17. "bytes"
  18. "errors"
  19. "io"
  20. "strconv"
  21. "strings"
  22. )
  23. // ParseAR parses an archive file from r and returns a map from filename to
  24. // contents, or else an error.
  25. func ParseAR(r io.Reader) (map[string][]byte, error) {
  26. // See https://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details
  27. const expectedMagic = "!<arch>\n"
  28. var magic [len(expectedMagic)]byte
  29. if _, err := io.ReadFull(r, magic[:]); err != nil {
  30. return nil, err
  31. }
  32. if string(magic[:]) != expectedMagic {
  33. return nil, errors.New("ar: not an archive file")
  34. }
  35. const filenameTableName = "//"
  36. const symbolTableName = "/"
  37. var longFilenameTable []byte
  38. ret := make(map[string][]byte)
  39. for {
  40. var header [60]byte
  41. if _, err := io.ReadFull(r, header[:]); err != nil {
  42. if err == io.EOF {
  43. break
  44. }
  45. return nil, errors.New("ar: error reading file header: " + err.Error())
  46. }
  47. name := strings.TrimRight(string(header[:16]), " ")
  48. sizeStr := strings.TrimRight(string(header[48:58]), "\x00 ")
  49. size, err := strconv.ParseUint(sizeStr, 10, 64)
  50. if err != nil {
  51. return nil, errors.New("ar: failed to parse file size: " + err.Error())
  52. }
  53. // File contents are padded to a multiple of two bytes
  54. storedSize := size
  55. if storedSize%2 == 1 {
  56. storedSize++
  57. }
  58. contents := make([]byte, storedSize)
  59. if _, err := io.ReadFull(r, contents); err != nil {
  60. return nil, errors.New("ar: error reading file contents: " + err.Error())
  61. }
  62. contents = contents[:size]
  63. switch {
  64. case name == filenameTableName:
  65. if longFilenameTable != nil {
  66. return nil, errors.New("ar: two filename tables found")
  67. }
  68. longFilenameTable = contents
  69. continue
  70. case name == symbolTableName:
  71. continue
  72. case len(name) > 1 && name[0] == '/':
  73. if longFilenameTable == nil {
  74. return nil, errors.New("ar: long filename reference found before filename table")
  75. }
  76. // A long filename is stored as "/" followed by a
  77. // base-10 offset in the filename table.
  78. offset, err := strconv.ParseUint(name[1:], 10, 64)
  79. if err != nil {
  80. return nil, errors.New("ar: failed to parse filename offset: " + err.Error())
  81. }
  82. if offset > uint64((^uint(0))>>1) {
  83. return nil, errors.New("ar: filename offset overflow")
  84. }
  85. if int(offset) > len(longFilenameTable) {
  86. return nil, errors.New("ar: filename offset out of bounds")
  87. }
  88. filename := longFilenameTable[offset:]
  89. if i := bytes.IndexByte(filename, '/'); i < 0 {
  90. return nil, errors.New("ar: unterminated filename in table")
  91. } else {
  92. filename = filename[:i]
  93. }
  94. name = string(filename)
  95. default:
  96. name = strings.TrimRight(name, "/")
  97. }
  98. ret[name] = contents
  99. }
  100. return ret, nil
  101. }