Advertisement
Guest User

Common Lisp Source Engine VPK Reader.

a guest
May 1st, 2023
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.11 KB | None | 0 0
  1. ;; LISP library for reading Valve Pak Files used by the Source Engine.
  2. (defconstant file-identifier #x55aa1234)
  3.  
  4. (defconstant archive-index/no-archive #x7fff
  5. "This constant indicates that a file is stored immediately after the directory tree and not stored in an archive-file.")
  6.  
  7. (defun read-vpk (input-byte-stream &aux (vpk-list (list 'version nil 'directory-tree (list 'size nil 'tree nil))))
  8. "Reads a VPK header, directory, and footer sections returns it described as a list. Does not read archive files."
  9.  
  10. (equalp file-identifier (let ((identifier (list 0 0 0 0)) (number 0) (index 0))
  11. (read-sequence identifier input-byte-stream)
  12. (map 'nil (lambda (b) (setf (ldb (byte 8 index) number) b) (incf index 8)) identifier)
  13. number
  14. ))
  15.  
  16. (let ((version (list 0 0 0 0)) (number 0) (index 0))
  17. (read-sequence version input-byte-stream)
  18. (map 'nil (lambda (b) (setf (ldb (byte 8 index) number) b) (incf index 8)) version)
  19. (setf (getf vpk-list 'version) number)
  20. )
  21.  
  22. (setf (getf (getf vpk-list 'directory-tree) 'size)
  23. (read-integer-seq-stream (list 0 0 0 0) input-byte-stream))
  24.  
  25. (if (>= (getf vpk-list 'version) 2)
  26. (setf
  27. (getf vpk-list 'file-data-section-size)
  28. (read-integer-seq-stream (list 0 0 0 0) input-byte-stream)
  29. (getf vpk-list 'archive-md5-section-size)
  30. (read-integer-seq-stream (list 0 0 0 0) input-byte-stream)
  31. (getf vpk-list 'external-md5-section-size)
  32. (read-integer-seq-stream (list 0 0 0 0) input-byte-stream)
  33. (getf vpk-list 'signature-section-size)
  34. (read-integer-seq-stream (list 0 0 0 0) input-byte-stream))
  35. )
  36. ;; Read the file contents.
  37. ;; 1. The extension
  38. ;; 2. The path
  39. ;; 3. The file name.
  40. (flet
  41. ((binary-string-to-string ()
  42. (do ((by-list '() (nconc by-list (list (read-byte input-byte-stream))))
  43. )
  44. ((eq (car (last by-list)) 0) (map 'string #'code-char by-list))))
  45. (read-file-entry () "Returns an entry for a file in a VPK and moves the stream reader after preload data."
  46. (let*
  47. ((crc (read-integer-seq-stream (list 0 0 0 0) input-byte-stream))
  48. (preload-bytes (read-integer-seq-stream (list 0 0) input-byte-stream))
  49. (archive-index (read-integer-seq-stream (list 0 0) input-byte-stream))
  50. (entry-offset (read-integer-seq-stream (list 0 0 0 0) input-byte-stream))
  51. (entry-length (read-integer-seq-stream (list 0 0 0 0) input-byte-stream))
  52. (end-seq-bytes (list nil nil))
  53. (preload-data (make-list preload-bytes)))
  54. (read-sequence preload-data input-byte-stream)
  55. (tagbody temp
  56. (read-sequence end-seq-bytes input-byte-stream)
  57. (if (equal end-seq-bytes (list #xFF #xFF))
  58. t (go temp)))
  59. (list 'crc crc 'preload-data (list 'size preload-bytes 'text preload-data) 'archive-index archive-index 'entry-offset entry-offset 'entry-length entry-length))
  60. ))
  61.  
  62.  
  63. (setf (getf (getf vpk-list 'directory-tree) 'tree)
  64. (do* ((extension-name nil (binary-string-to-string))
  65. (extension-entry nil (list 'paths
  66. (if (string-equal extension-name "�")
  67. nil
  68. (do* (
  69. (path-name nil (binary-string-to-string))
  70. (path-entry nil (list 'files
  71. (if (string-equal path-name "�")
  72. nil
  73. (do* ((file-name nil (binary-string-to-string))
  74. (file-entry nil (if (string-equal file-name "�") nil (read-file-entry)))
  75. (file-list (list) (append file-list (list (cons file-name file-entry)))))
  76. ((string-equal file-name "�") file-list)
  77. ))))
  78. (path-list nil (append path-list
  79. (list (cons path-name path-entry))))
  80. )
  81. ((string-equal path-name "�") path-list)
  82. ))))
  83. (extension-list (list)
  84. (append extension-list
  85. (list (cons extension-name extension-entry)))))
  86. ((string-equal extension-name "�") extension-list)
  87. ))
  88. )
  89. (if (>= (getf vpk-list 'version) 2)
  90. t
  91. (return-from read-vpk vpk-list)
  92. )
  93.  
  94. (file-position input-byte-stream (+ (file-position input-byte-stream) (getf vpk-list 'file-data-section-size)))
  95. (file-position input-byte-stream (+ (file-position input-byte-stream) (getf vpk-list 'archive-md5-section-size) ))
  96. ;; Content checksum
  97. (if (= (getf vpk-list 'external-md5-section-size) 48)
  98. (progn
  99. (file-position input-byte-stream (+ (file-position input-byte-stream) (getf vpk-list 'external-md5-section-size)))
  100. (setf (getf (getf vpk-list 'directory-tree) 'checksum) (read-integer-seq-stream (make-list 16 :initial-element 0) input-byte-stream))
  101. (setf (getf (getf vpk-list 'directory-tree) 'archive-md5-section-checksum) (read-integer-seq-stream (make-list 16 :initial-element 0) input-byte-stream))
  102. (setf (getf vpk-list 'unknown) (read-integer-seq-stream (make-list 16 :initial-element 0) input-byte-stream))
  103. )
  104. )
  105. (if (> (getf vpk-list 'signature-section-size) 0)
  106. (progn
  107. (file-position input-byte-stream (+ (file-position input-byte-stream) (getf vpk-list 'signature-section-size)))
  108. (setf (getf (getf vpk-list 'signature) 'public-key) (read-integer-seq-stream (make-list (read-integer-seq-stream (list 0 0 0 0) input-byte-stream) :initial-element 0) input-byte-stream))
  109. (setf (getf (getf vpk-list 'signature) 'signature) (read-integer-seq-stream (make-list (read-integer-seq-stream (list 0 0 0 0) input-byte-stream) :initial-element 0) input-byte-stream))
  110. )
  111. )
  112. ;; Return the result property-list for the VPK.
  113. vpk-list
  114. )
  115.  
  116. ;; Documentation
  117. (setf (documentation 'archive 'specification) "A file which stores data chunk for a Chunk-separated VPK. They are numbered based on the index of a particular VPK .")
  118. ;; Utilities.
  119.  
  120. (defun convert-byte-list-to-integer (byte-list &aux (iterator 0) (number 0))
  121. (map 'nil (lambda (byt) (setf (ldb (byte 8 iterator) number) byt) (incf iterator 8)) byte-list)
  122. number
  123. )
  124.  
  125. (defun read-integer-seq-stream (byte-list input-byte-stream)
  126. (let ((by-list byte-list))
  127. (read-sequence by-list input-byte-stream)
  128. (convert-byte-list-to-integer by-list)))
  129.  
  130.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement