Разница в реализации zlib между nodejs [13.13.0] и ruby [2.5.1p57] - PullRequest
1 голос
/ 07 мая 2020

Я изучаю внутреннее устройство git, и это дерево в моем репозитории:

git cat-file 88e38705fdbd3608cddbe904b67c731f3234c45b -p
100644 blob ce013625030ba8dba906f756967f9e9ca394464a    hello.txt
100644 blob cc628ccd10742baea8241c5924df992b5c019f71    world.txt

Когда я использую zlib Ruby с:

puts Zlib::Inflate.inflate(STDIN.read)

и вывод по конвейеру с помощью hexdump -C:

cat .git/objects/88/e38705fdbd3608cddbe904b67c731f3234c45b | rinflate | hexdump -C

это результат:

00000000  74 72 65 65 20 37 34 00  31 30 30 36 34 34 20 68  |tree 74.100644 h|
00000010  65 6c 6c 6f 2e 74 78 74  00 ce 01 36 25 03 0b a8  |ello.txt...6%...|
00000020  db a9 06 f7 56 96 7f 9e  9c a3 94 46 4a 31 30 30  |....V......FJ100|
00000030  36 34 34 20 77 6f 72 6c  64 2e 74 78 74 00 cc 62  |644 world.txt..b|
00000040  8c cd 10 74 2b ae a8 24  1c 59 24 df 99 2b 5c 01  |...t+..$.Y$..+\.|
00000050  9f 71                                             |.q|
00000052

Однако, когда я использую NodeJS:

  const zlib = require("zlib");
  const fs = require("fs");
  fs.writeFileSync("/dev/stdout", zlib.inflateSync(fs.readFileSync("/dev/stdin")).toString());

Я получаю такой вывод:

00000000  74 72 65 65 20 37 34 00  31 30 30 36 34 34 20 68  |tree 74.100644 h|
00000010  65 6c 6c 6f 2e 74 78 74  00 ef bf bd 01 36 25 03  |ello.txt.....6%.|
00000020  0b ef bf bd db a9 06 ef  bf bd 56 ef bf bd 7f ef  |..........V.....|
00000030  bf bd ef bf bd ef bf bd  ef bf bd 46 4a 31 30 30  |...........FJ100|
00000040  36 34 34 20 77 6f 72 6c  64 2e 74 78 74 00 ef bf  |644 world.txt...|
00000050  bd 62 ef bf bd ef bf bd  10 74 2b ef bf bd ef bf  |.b.......t+.....|
00000060  bd 24 1c 59 24 df 99 2b  5c 01 ef bf bd 71        |.$.Y$..+\....q|

Почему такая разница? И как я могу сделать так, чтобы NodeJS и Ruby выводили одно и то же?

1 Ответ

1 голос
/ 08 мая 2020

В JavaScript строка представляет собой последовательность символов Юникода, закодированных в UTF-16. Вы не можете хранить нетекстовое содержимое в строке JavaScript, так как она не обеспечивает возможности хранения в любой другой кодировке.

Однако объекты дерева Git являются двоичными и содержат криптографию. c ha sh в двоичном формате (обычно SHA-1), поэтому они не будут иметь текстового содержимого и не могут быть сохранены в строке JavaScript. Если вы все равно попытаетесь это сделать, вы получите замену неверных байтовых значений на U + FFFD, символ замены, который закодирован в UTF-8 как 0xef 0xbf 0xbd, что приведет к повреждению данных.

Если вы не вызываете toString(), ваши данные хранятся в каком-то двоичном буферном объекте и содержат именно те байты, которые декодированы zlib.

Ruby, с другой стороны, имеет кодировку для каждой строки и может хранить двоичные строки с кодировкой ASCII-8BIT (также известной как BINARY). Так что, если бы у вас был код Ruby, это, вероятно, сработало бы нормально.

...