Проблема 1: Файл открыт в текстовом режиме
Когда вы читаете файл в тексте, возможны все виды полезных преобразований, которые наиболее бесполезны при работе с двоичным файлом. Наиболее распространенным является Windows возврат каретки и перевод строки в конец строки (обычно 0x0D0A), переводимый в новую строку (обычно 0x0A) или наоборот.
Решение 1. Откройте файл в двоичном режиме
std::ifstream fs("zip file to read", std::ios::binary);
Проблема 2: Расширение знака на символах.
Эта простая программа
#include <iostream>
#include <iomanip>
int main() {
char buf2[4] = {(char)0x80, 0x55, 0x55, 0x55};
long size=buf2[0]|buf2[1]<<8|buf2[2]<<16|buf2[3]<<24;
std::cout << std::hex << size;
return 0;
}
должна распечатать 55555580, верно?
Нет. Он может выводить ffffff80.
Как?
При использовании в арифметике 0x80 c buf2[0]
преобразуется в int
(или что-то большее, если необходимо), а если char
подписано, знак будет сохранен. 0x80 расширяется до 0xFFFFFF80. И все эти лишние 1 бит разбивают havo c на двоичные операции, когда int
собирается из байтов.
Примечание: смотрите, как мне пришлось привести 0x80, чтобы он соответствовал? Первый признак того, что что-то идет не так, go часто является актером.
Решение 2
Используйте unsigned char
int main() {
unsigned char buf2[4] = {0x80, 0x55, 0x55, 0x55};
// note that the cast isn't needed any more
long size=buf2[0]|buf2[1]<<8|buf2[2]<<16|buf2[3]<<24;
std::cout << std::hex << size;
return 0;
}
или замаскируйте расширенные биты.
int main() {
char buf2[4] = {(char)0x80, 0x55, 0x55, 0x55};
long size=buf2[0] & 0x000000FF |
buf2[1]<<8 & 0x0000FF00 |
buf2[2]<<16 & 0x00FF0000 |
buf2[3]<<24 & 0xFF000000;
std::cout << std::hex << size;
return 0;
}
примечание: long может не быть 32 бит, и вы все еще можете войти в мир боли. Используйте Fixed Width Integer из cstdint, чтобы убедиться, что вы всегда работаете с данными правильного размера, когда это важно. Здесь это имеет значение.