Common::SeekableReadStream *ERFFile::decompressHeaderlessZlib(byte *compressedData, uint32 packedSize, uint32 unpackedSize) const { try { Common::SeekableReadStream *stream = decompressZlib(compressedData, packedSize, unpackedSize, MAX_WBITS); delete[] compressedData; return stream; } catch (Common::Exception &e) { delete[] compressedData; throw; } }
// decompress(data, method) int ModApiUtil::l_decompress(lua_State *L) { size_t size; const char *data = luaL_checklstring(L, 1, &size); std::istringstream is(std::string(data, size)); std::ostringstream os; decompressZlib(is, os); std::string out = os.str(); lua_pushlstring(L, out.data(), out.size()); return 1; }
void decompress(std::istream &is, std::ostream &os, u8 version) { if(version >= 11) { decompressZlib(is, os); return; } // Read length (u32) u8 tmp[4]; is.read((char*)tmp, 4); u32 len = readU32(tmp); // We will be reading 8-bit pairs of more_count and byte u32 count = 0; for(;;) { u8 more_count=0; u8 byte=0; is.read((char*)&more_count, 1); is.read((char*)&byte, 1); if(is.eof()) throw SerializationError("decompress: stream ended halfway"); for(s32 i=0; i<(u16)more_count+1; i++) os.write((char*)&byte, 1); count += (u16)more_count+1; if(count == len) break; } }
void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())<<std::endl); m_day_night_differs_expired = false; if(version <= 21) { deSerialize_pre22(is, version, disk); return; } u8 flags = readU8(is); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; m_generated = (flags & 0x08) ? false : true; /* Bulk node data */ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Bulk node data"<<std::endl); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u8 content_width = readU8(is); u8 params_width = readU8(is); if(content_width != 1 && content_width != 2) throw SerializationError("MapBlock::deSerialize(): invalid content_width"); if(params_width != 2) throw SerializationError("MapBlock::deSerialize(): invalid params_width"); MapNode::deSerializeBulk(is, version, data, nodecount, content_width, params_width, true); /* NodeMetadata */ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Node metadata"<<std::endl); // Ignore errors try{ std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); if(version >= 23) m_node_metadata.deSerialize(iss, m_gamedef); else content_nodemeta_deserialize_legacy(iss, &m_node_metadata, &m_node_timers, m_gamedef); } catch(SerializationError &e) { errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata at (" <<PP(getPos())<<": "<<e.what()<<std::endl; } /* Data that is only on disk */ if(disk) { // Node timers if(version == 23){ // Read unused zero readU8(is); } else if(version >= 24){ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Node timers"<<std::endl); m_node_timers.deSerialize(is); } // Static objects TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Static objects"<<std::endl); m_static_objects.deSerialize(is); // Timestamp TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Timestamp"<<std::endl); setTimestamp(readU32(is)); m_disk_timestamp = m_timestamp; // Dynamically re-set ids based on node names TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": NameIdMapping"<<std::endl); NameIdMapping nimap; nimap.deSerialize(is); correctBlockNodeIds(&nimap, data, m_gamedef); }
void MapBlock::deSerialize(std::istream &is, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); // These have no lighting info if(version <= 1) { setLightingExpired(true); } // These have no "generated" field if(version < 18) { m_generated = true; } // These have no compression if(version <= 3 || version == 5 || version == 6) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; for(u32 i=0; i<nodecount; i++) { s32 len = MapNode::serializedLength(version); SharedBuffer<u8> d(len); is.read((char*)*d, len); if(is.gcount() != len) throw SerializationError ("MapBlock::deSerialize: no enough input data"); data[i].deSerialize(*d, version); } } else if(version <= 10) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u8 t8; is.read((char*)&t8, 1); is_underground = t8; { // Uncompress and set material data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { data[i].param0 = s[i]; } } { // Uncompress and set param data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { data[i].param1 = s[i]; } } if(version >= 10) { // Uncompress and set param2 data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { data[i].param2 = s[i]; } } } // All other versions (newest) else { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u8 flags; is.read((char*)&flags, 1); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; if(version >= 18) m_generated = (flags & 0x08) ? false : true; // Uncompress data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount*3) throw SerializationError ("MapBlock::deSerialize: decompress resulted in size" " other than nodecount*3"); // deserialize nodes from buffer for(u32 i=0; i<nodecount; i++) { u8 buf[3]; buf[0] = s[i]; buf[1] = s[i+nodecount]; buf[2] = s[i+nodecount*2]; data[i].deSerialize(buf, version); } /* NodeMetadata */ if(version >= 14) { // Ignore errors try{ if(version <= 15) { std::string data = deSerializeString(is); std::istringstream iss(data, std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } else { //std::string data = deSerializeLongString(is); std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } } catch(SerializationError &e) { errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata"<<std::endl; } } } }
void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; // Initialize default flags is_underground = false; m_day_night_differs = false; m_lighting_expired = false; m_generated = true; // Make a temporary buffer u32 ser_length = MapNode::serializedLength(version); SharedBuffer<u8> databuf_nodelist(nodecount * ser_length); // These have no compression if(version <= 3 || version == 5 || version == 6) { char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; is.read((char*)*databuf_nodelist, nodecount * ser_length); if(is.gcount() != nodecount * ser_length) throw SerializationError ("MapBlock::deSerialize: no enough input data"); } else if(version <= 10) { u8 t8; is.read((char*)&t8, 1); is_underground = t8; { // Uncompress and set material data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length] = s[i]; } } { // Uncompress and set param data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length + 1] = s[i]; } } if(version >= 10) { // Uncompress and set param2 data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length + 2] = s[i]; } } } // All other versions (newest) else { u8 flags; is.read((char*)&flags, 1); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; if(version >= 18) m_generated = (flags & 0x08) ? false : true; // Uncompress data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount*3) throw SerializationError ("MapBlock::deSerialize: decompress resulted in size" " other than nodecount*3"); // deserialize nodes from buffer for(u32 i=0; i<nodecount; i++) { databuf_nodelist[i*ser_length] = s[i]; databuf_nodelist[i*ser_length + 1] = s[i+nodecount]; databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2]; } /* NodeMetadata */ if(version >= 14) { // Ignore errors try{ if(version <= 15) { std::string data = deSerializeString(is); std::istringstream iss(data, std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } else { //std::string data = deSerializeLongString(is); std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } } catch(SerializationError &e) { errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata"<<std::endl; } } } // Deserialize node data for(u32 i=0; i<nodecount; i++) { data[i].deSerialize(&databuf_nodelist[i*ser_length], version); } if(disk) { /* Versions up from 9 have block objects. (DEPRECATED) */ if(version >= 9){ u16 count = readU16(is); // Not supported and length not known if count is not 0 if(count != 0){ errorstream<<"WARNING: MapBlock::deSerialize_pre22(): " <<"Ignoring stuff coming at and after MBOs"<<std::endl; return; } } /* Versions up from 15 have static objects. */ if(version >= 15) m_static_objects.deSerialize(is); // Timestamp if(version >= 17){ setTimestamp(readU32(is)); m_disk_timestamp = m_timestamp; } else { setTimestamp(BLOCK_TIMESTAMP_UNDEFINED); } // Dynamically re-set ids based on node names NameIdMapping nimap; // If supported, read node definition id mapping if(version >= 21){ nimap.deSerialize(is); // Else set the legacy mapping } else { content_mapnode_get_name_id_mapping(&nimap); } correctBlockNodeIds(&nimap, data, m_gamedef); } // Legacy data changes // This code has to convert from pre-22 to post-22 format. INodeDefManager *nodedef = m_gamedef->ndef(); for(u32 i=0; i<nodecount; i++) { const ContentFeatures &f = nodedef->get(data[i].getContent()); // Mineral if(nodedef->getId("default:stone") == data[i].getContent() && data[i].getParam1() == 1) { data[i].setContent(nodedef->getId("default:stone_with_coal")); data[i].setParam1(0); } else if(nodedef->getId("default:stone") == data[i].getContent() && data[i].getParam1() == 2) { data[i].setContent(nodedef->getId("default:stone_with_iron")); data[i].setParam1(0); } // facedir_simple if(f.legacy_facedir_simple) { data[i].setParam2(data[i].getParam1()); data[i].setParam1(0); } // wall_mounted if(f.legacy_wallmounted) { u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0}; u8 dir_old_format = data[i].getParam2(); u8 dir_new_format = 0; for(u8 j=0; j<8; j++) { if((dir_old_format & wallmounted_new_to_old[j]) != 0) { dir_new_format = j; break; } } data[i].setParam2(dir_new_format); } } }