2
0

gzip.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* jshint esversion: 6 */
  2. /* global pako */
  3. var gzip = gzip || {};
  4. gzip.Archive = class {
  5. constructor(buffer) {
  6. this._entries = [];
  7. if (buffer.length < 18 || buffer[0] != 0x1f || buffer[1] != 0x8b) {
  8. throw new gzip.Error('Invalid gzip archive.');
  9. }
  10. const reader = new gzip.Reader(buffer, 0, buffer.length);
  11. this._entries.push(new gzip.Entry(reader));
  12. }
  13. get entries() {
  14. return this._entries;
  15. }
  16. };
  17. gzip.Entry = class {
  18. constructor(reader) {
  19. if (!reader.match([ 0x1f, 0x8b ])) {
  20. throw new gzip.Error('Invalid gzip signature.');
  21. }
  22. const compressionMethod = reader.byte();
  23. if (compressionMethod != 8) {
  24. throw new gzip.Error("Invalid compression method '" + compressionMethod.toString() + "'.");
  25. }
  26. const flags = reader.byte();
  27. reader.uint32(); // MTIME
  28. reader.byte();
  29. reader.byte(); // OS
  30. if ((flags & 4) != 0) {
  31. const xlen = reader.uint16();
  32. reader.skip(xlen);
  33. }
  34. if ((flags & 8) != 0) {
  35. this._name = reader.string();
  36. }
  37. if ((flags & 16) != 0) { // FLG.FCOMMENT
  38. reader.string();
  39. }
  40. if ((flags & 1) != 0) {
  41. reader.uint16(); // CRC16
  42. }
  43. const compressedData = reader.bytes();
  44. if (typeof process === 'object' && typeof process.versions == 'object' && typeof process.versions.node !== 'undefined') {
  45. this._data = require('zlib').inflateRawSync(compressedData);
  46. }
  47. else if (typeof pako !== 'undefined') {
  48. this._data = pako.inflateRaw(compressedData);
  49. }
  50. else {
  51. this._data = new require('./zip').Inflater().inflateRaw(compressedData);
  52. }
  53. reader.position = -8;
  54. reader.uint32(); // CRC32
  55. const size = reader.uint32();
  56. if (size != this._data.length) {
  57. throw new gzip.Error('Invalid size.');
  58. }
  59. }
  60. get name() {
  61. return this._name;
  62. }
  63. get data() {
  64. return this._data;
  65. }
  66. };
  67. gzip.Reader = class {
  68. constructor(buffer, start, end) {
  69. this._buffer = buffer;
  70. this._position = start;
  71. this._end = end;
  72. this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  73. }
  74. match(signature) {
  75. if (this._position + signature.length <= this._end) {
  76. for (let i = 0; i < signature.length; i++) {
  77. if (this._buffer[this._position + i] != signature[i]) {
  78. return false;
  79. }
  80. }
  81. }
  82. this._position += signature.length;
  83. return true;
  84. }
  85. get position() {
  86. return this._position;
  87. }
  88. set position(value) {
  89. this._position = value >= 0 ? value : this._end + value;
  90. }
  91. skip(offset) {
  92. this._position += offset;
  93. if (this._position > this._end) {
  94. throw new gzip.Error('Expected ' + (this._position - this._end) + ' more bytes. The file might be corrupted. Unexpected end of file.');
  95. }
  96. }
  97. bytes(size) {
  98. const position = this._position;
  99. size = size === undefined ? (this._end - position) : size;
  100. this.skip(size);
  101. return this._buffer.subarray(position, this._position);
  102. }
  103. byte() {
  104. const position = this._position;
  105. this.skip(1);
  106. return this._buffer[position];
  107. }
  108. uint16() {
  109. const position = this._position;
  110. this.skip(2);
  111. return this._view.getUint16(position, true);
  112. }
  113. uint32() {
  114. const position = this._position;
  115. this.skip(4);
  116. return this._view.getUint32(position, true);
  117. }
  118. string() {
  119. let result = '';
  120. const end = this._buffer.indexOf(0x00, this._position);
  121. if (end < 0) {
  122. throw new gzip.Error('End of string not found.');
  123. }
  124. while (this._position < end) {
  125. result += String.fromCharCode(this._buffer[this._position++]);
  126. }
  127. this._position++;
  128. return result;
  129. }
  130. };
  131. gzip.Error = class extends Error {
  132. constructor(message) {
  133. super(message);
  134. this.name = 'Gzip Error';
  135. }
  136. };
  137. if (typeof module !== 'undefined' && typeof module.exports === 'object') {
  138. module.exports.Archive = gzip.Archive;
  139. }