Ejemplo n.º 1
0
bool FieldParser::ParseVector3Field(ESMStream& stream, uint16_t length, Vector3F& outVector) {
    if (length <= sizeof(float) * 3)
        return false;
    
    stream.ReadRaw(&outVector.X, sizeof(outVector.X));
    stream.ReadRaw(&outVector.Y, sizeof(outVector.Y));
    stream.ReadRaw(&outVector.Z, sizeof(outVector.Z));
    
    return true;
}
Ejemplo n.º 2
0
bool FalloutESM::ParseStatics(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::STAT) {
            mLoadMessages.push_back("Error: encountered an invalid record in the static object group");
            return false;
        }
        
        ESMStream recordStream(substream, header.Size);
        StaticObject object(StaticObjectType::Static, header.Meta.AsRecord.FormID);
        
        if (object.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: error parsing a static object record");
            return false;
        }
        
        mStaticObjects.insert(std::pair<FormIdentifier, StaticObject>(header.Meta.AsRecord.FormID, std::move(object)));
        mEntityTypeMap.insert(std::pair<FormIdentifier, ESMTag>(header.Meta.AsRecord.FormID, ESMTag::STAT));
    }
    
    return true;
}
Ejemplo n.º 3
0
bool FieldParser::ParseBinaryField(ESMStream& stream, uint16_t length, std::vector<uint8_t>& outVector) {
    outVector.resize(length);
    
    stream.ReadRaw(&outVector[0], length);
    
    return true;
}
Ejemplo n.º 4
0
bool FieldParser::ParseOFSTField(ESMStream& stream, uint32_t length, std::vector<uint32_t>& outValue) {
    outValue.reserve(length / sizeof(uint32_t));
    
    stream.ReadRaw(&outValue[0], length);
    
    return true;
}
Ejemplo n.º 5
0
bool FieldParser::ParseEDIDField(ESMStream& stream, uint16_t length, std::string& outValue) {
    if (length == 0)
        return true;
    
    stream.ReadCString(length, outValue);
    return true;
}
Ejemplo n.º 6
0
bool FalloutESM::ParseTextureSets(ESMStream& substream) {
    
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::TXST) {
            mLoadMessages.push_back("Error: encountered a non-texture set record in the texture set group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        TextureSet set(record.Meta.AsRecord.FormID);
        
        if (set.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: encountered a malformed texture set record");
            return false;
        }
        
        mTextures.insert(std::pair<FormIdentifier, TextureSet>(record.Meta.AsRecord.FormID, std::move(set)));
    }
    
    return true;
}
Ejemplo n.º 7
0
bool TextureSet::Parse(ESMStream& stream) {
    
    while(stream.IsValid() == true) {
        FieldHeader fieldHeader;
        
        stream.ReadFieldHeader(fieldHeader);
        
        switch(fieldHeader.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, fieldHeader.Size, mEditorId);
                break;
                
            case ESMTag::OBND:
                FieldParser::ParseOBDNField(stream, fieldHeader.Size, mBounds);
                break;
                
            case ESMTag::TX00:
            case ESMTag::TX01:
            case ESMTag::TX02:
            case ESMTag::TX03:
            case ESMTag::TX04:
            case ESMTag::TX05:
            case ESMTag::TX06:
            case ESMTag::TX07:
            {
                std::string textureName;
                FieldParser::ParseTXNNField(stream, fieldHeader.Size, textureName);
                
                mTextureNames.push_back(std::move(textureName));
                break;
            }
                
            case ESMTag::DODT:
                FieldParser::ParseDODTField(stream, fieldHeader.Size, mDecalData);
                break;
                
            case ESMTag::DNAM:
                stream.Read16((uint16_t&)mFlags);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 8
0
bool FalloutScript::Parse(ESMStream& stream) {
    while(stream.IsValid() == true) {
        FieldHeader header;
        
        stream.ReadFieldHeader(header);
        
        switch(header.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, header.Size, mEditorID);
                break;
                
            case ESMTag::SCHR:
                FieldParser::ParseSCHRField(stream, header.Size, mScriptHeader);
                break;
                
            case ESMTag::SCDA:
                FieldParser::ParseBinaryField(stream, header.Size, mScriptBytecode);
                break;
                
            case ESMTag::SCTX:
                FieldParser::ParseEDIDField(stream, header.Size, mScriptSource);
                break;
                
            case ESMTag::SCRO:
            {
                FormIdentifier id = 0;
                
                FieldParser::ParseFormID(stream, header.Size, id);
                mReferences.push_back(id);
                break;
            }   
            
            case ESMTag::SCVR:
            case ESMTag::SCRV: //TODO: This is undocumented, fixed uint32_t field
            case ESMTag::SLSD:
                //TODO: Handle these
                stream.Skip(header.Size);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 9
0
bool FieldParser::ParseFormID(ESMStream& stream, uint16_t length, FormIdentifier& outValue) {
    if (length != sizeof(outValue))
        return false;
    
    stream.ReadRaw(&outValue, sizeof(outValue));
    
    return true;
}
Ejemplo n.º 10
0
bool FieldParser::ParseByteValue(ESMStream& stream, uint16_t length, uint8_t& outValue) {
    if (length != sizeof(outValue))
        return false;
    
    stream.ReadRaw(&outValue, sizeof(outValue));
    
    return true;
}
Ejemplo n.º 11
0
bool FieldParser::ParseHavokData(ESMStream& stream, uint16_t length, LandTextureHavokData& havokData) {
    if (length != sizeof(havokData))
        return false;
    
    stream.ReadRaw(&havokData, sizeof(havokData));
    
    return true;
}
Ejemplo n.º 12
0
bool FieldParser::ParseSCHRField(ESMStream& stream, uint16_t length, SCHRField& outField) {
    if (length != sizeof(outField))
        return false;
    
    stream.ReadRaw(&outField, sizeof(outField));
    
    return true;
}
Ejemplo n.º 13
0
bool FieldParser::ParseXCLCField(ESMStream& stream, uint16_t length, XCLCField& outField) {
    //FIXME: According to the documents this is a 12 byte field, however I'm encountering only 8 bytes.
    if (length != sizeof(outField))
    {
        if (length == sizeof(uint32_t) * 2) {
            stream.Read32((uint32_t &)outField.X);
            stream.Read32((uint32_t &)outField.Y);
            
            outField.LandHideFlags = LandHideFlag::None;
            return true;
        }
        
        return false;
    }
    
    stream.ReadRaw(&outField, sizeof(outField));
    
    return true;
}
Ejemplo n.º 14
0
bool LandscapeTextureSet::Parse(ESMStream& stream) {
    while(stream.IsValid() == true) {
        FieldHeader header;
        
        stream.ReadFieldHeader(header);
        
        switch(header.Tag) {
            case ESMTag::EDID:
                FieldParser::ParseEDIDField(stream, header.Size, mEditorId);
                break;
                
            case ESMTag::ICON:
                FieldParser::ParseEDIDField(stream, header.Size, mLargeIconFilename);
                break;
                
            case ESMTag::MICO:
                FieldParser::ParseEDIDField(stream, header.Size, mSmallIconFilename);
                break;
                
            case ESMTag::TNAM:
                FieldParser::ParseFormID(stream, header.Size, mTextureIdentifier);
                break;
                
            case ESMTag::HNAM:
                FieldParser::ParseHavokData(stream, header.Size, mHavokData);
                break;
                
            case ESMTag::SNAM:
                FieldParser::ParseByteValue(stream, header.Size, mSpecularExponent);
                break;
                
            case ESMTag::GNAM:
                FieldParser::ParseFormID(stream, header.Size, mGrassIdentifier);
                break;
                
            default:
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 15
0
bool FalloutESM::ParseWorldCellGroup(ESMStream& stream, FormIdentifier parentWorld) {
    auto worldItr = mWorldspaces.find(parentWorld);
    
    if (worldItr == mWorldspaces.end()) {
        mLoadMessages.push_back("Error: trying to add entites to a non-existent world");
        return false;
    }
    
    Worldspace& world = (*worldItr).second;
    
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseWorldInnerGroup(stream, world, header, 0, 0) == false) {
                    mLoadMessages.push_back("Error: unable to parse world cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream cellStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, -1, -1);
                
                if (cell.Parse(cellStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record in the world group");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                world.GetCellsWritable().push_back(header.Meta.AsRecord.FormID);
                break;
            }
            
            default:
                mLoadMessages.push_back("Error: invalid tag inside the world cell group");
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 16
0
bool FalloutESM::ParseCellExteriorGroup(ESMStream& stream, Worldspace& world, int x, int y, bool isblock) {
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseWorldInnerGroup(stream, world, header, x, y) == false) {
                    mLoadMessages.push_back("Error: unable to parse world exterior cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream recordStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, x, y, isblock);
                
                if (cell.Parse(recordStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record in the world group");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                world.GetCellsWritable().push_back(header.Meta.AsRecord.FormID);
                break;
            }
                
            default:
            {
                mLoadMessages.push_back("Error: invalid tag inside a world exterior cell group");
                break;
            }
        }
    }
    
    return true;
}
Ejemplo n.º 17
0
bool FalloutESM::ParseWorlds(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                ESMStream groupStream(substream, header.Size - sizeof(RecordHeader));
                
                if (ParseWorldCellGroup(groupStream, header.Meta.AsGroup.Label.AsFormIdentifier) == false) {
                    mLoadMessages.push_back("Error: unable to parse world cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::WRLD:
            {
                ESMStream worldStream(substream, header.Size);
                
                Worldspace world(header.Meta.AsRecord.FormID);
                
                if (world.Parse(worldStream) == false) {
                    mLoadMessages.push_back("Error: invalid world record");
                    return false;
                }
                
                mWorldspaces.insert(std::pair<FormIdentifier, Worldspace>(header.Meta.AsRecord.FormID, std::move(world)));
                break;
            }
            
            default:
                return false;
        }
        
    }
    
    return true;
}
Ejemplo n.º 18
0
bool FalloutESM::ParseCells(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::GRUP) {
            mLoadMessages.push_back("Error: found a non-group record in the top level cell structure");
            return false;
        }
        
        //These are all groups of type 2 (interior cell block)
        ESMStream groupStream(substream, header.Size - sizeof(RecordHeader));
        
        if (ParseCellGroup(substream, -1, -1) == false) {            
            return false;
        }
    }
    
    return true;
}
Ejemplo n.º 19
0
bool FalloutESM::ParseCellGroup(ESMStream& stream, int block, int subblock) {
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            case ESMTag::GRUP:
            {
                if (ParseCellInnerGroup(stream, header, block, subblock) == false) {
                    mLoadMessages.push_back("Error: unable to parse cell group");
                    return false;
                }
                
                break;
            }
            
            case ESMTag::CELL:
            {
                ESMStream cellStream(stream, header.Size);
                
                Cell cell(header.Meta.AsRecord.FormID, block, subblock);
                
                if (cell.Parse(cellStream) == false) {
                    mLoadMessages.push_back("Error: invalid cell record");
                    return false;
                }
                
                mCells.insert(std::pair<FormIdentifier, Cell>(header.Meta.AsRecord.FormID, std::move(cell)));
                break;
            }
            
            default:
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 20
0
bool FalloutESM::ParseMessages(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(substream, header);
        
        if (header.Tag != ESMTag::MESG) {
            mLoadMessages.push_back("Error: encountered an invalid record in the messages group");
            return false;
        }
        
        ESMStream recordStream(substream, header.Size);
        Message message(header.Meta.AsRecord.FormID);
        
        if (message.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: error parsing a message record");
            return false;
        }

        mMessages.insert(std::pair<FormIdentifier, Message>(header.Meta.AsRecord.FormID, std::move(message)));
    }
    
    return true;
}
Ejemplo n.º 21
0
bool FalloutESM::ParseGameSettings(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::GMST) {
            mLoadMessages.push_back("Error: encountered a non-GMST tag in the game settings group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        GameSetting setting(record.Meta.AsRecord.FormID);
        
        if (setting.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed GMST record");
            return false;
        }
        
        mSettings.insert(std::pair<FormIdentifier, GameSetting>(record.Meta.AsRecord.FormID, std::move(setting)));
    }
    
    return true;
}
Ejemplo n.º 22
0
bool FalloutESM::ParseScripts(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::SCPT) {
            mLoadMessages.push_back("Error: encountered a non-script record in the script group");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        FalloutScript script(record.Meta.AsRecord.FormID);
        
        if (script.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed script record");
            return false;
        }
        
        mScripts.insert(std::pair<FormIdentifier, FalloutScript>(record.Meta.AsRecord.FormID, std::move(script)));
    }
    
    return true;
}
Ejemplo n.º 23
0
bool FalloutESM::ParseLandTextureSets(ESMStream& substream) {
    while(substream.IsValid() == true) {
        RecordHeader record;
        
        ParseRecordHeader(substream, record);
        
        if (record.Tag != ESMTag::LTEX) {
            mLoadMessages.push_back("Error: encountered a non-land-texture set record");
            return false;
        }
        
        ESMStream recordStream(substream, record.Size);
        LandscapeTextureSet textureSet(record.Meta.AsRecord.FormID);
        
        if (textureSet.Parse(recordStream) == false) {
            mLoadMessages.push_back("Error: malformed land-texture set record");
            return false;
        }
        
        mLandTextures.insert(std::pair<FormIdentifier, LandscapeTextureSet>(record.Meta.AsRecord.FormID, std::move(textureSet)));
    }
    
    return true;
}
Ejemplo n.º 24
0
bool FalloutESM::ParseHeader(ESMStream& primaryStream) {
    RecordHeader header;
    
    ParseRecordHeader(primaryStream, header);
    
    if (header.Tag != ESMTag::TES4 || header.Size > primaryStream.GetSize()) {
        mLoadMessages.push_back("Error: the opening record was not valid. Expected 'TES4'");
        return false;
    }
    
    ESMStream recordStream(primaryStream, header.Size);
    
    while(recordStream.IsValid() == true) {
        FieldHeader header;
        recordStream.ReadFieldHeader(header);
        
        //TODO: Consume the header data
        switch(header.Tag) {
            case ESMTag::HEDR:  
            case ESMTag::OFST:  
            case ESMTag::CNAM: 
            case ESMTag::SNAM:
            case ESMTag::MAST:
            case ESMTag::DATA:
            case ESMTag::ONAM:
                recordStream.Skip(header.Size);
                break;
                
            default:
                mLoadMessages.push_back("Error: encountered an invalid tag type inside the TES4 header");
                return false;
        }
    }
    
    return true;
}
Ejemplo n.º 25
0
void ParseRecordHeader(ESMStream& stream, RecordHeader& header) {
    //FIXME: This is not portable.
    stream.ReadRaw(&header, sizeof(header));
}
Ejemplo n.º 26
0
bool FalloutESM::ParseCellChildren(FormIdentifier cellID, CellChildType childType, ESMStream& stream, int block, int subblock) {
    auto cellItr = mCells.find(cellID);
    // = mCells[cellID];
    
    if (cellItr == mCells.end()) {
        mLoadMessages.push_back("Error: tried to add children for a non-existent cell");
        return false;
    }
    
    Cell& cell = (*cellItr).second;
    
    while(stream.IsValid() == true) {
        RecordHeader header;
        
        ParseRecordHeader(stream, header);
        
        switch(header.Tag) {
            // Static objects
            case ESMTag::REFR: 
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Static, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid REFR record");
                    return false;
                }
                
                cell.AddObject(childType, obj);
                break;
            }
            
            // Creatures
            case ESMTag::ACRE:
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Creature, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid ACRE record");
                    return false;
                }
                
                cell.AddObject(childType,obj);
                break;
            }
            
            // Grenades
            case ESMTag::PGRE:
            {
                ESMStream substream(stream, header.Size);
                substream.Skip(substream.GetSize());
                break;
            }
            
            // Missiles
            case ESMTag::PMIS:
            {
                ESMStream substream(stream, header.Size);
                substream.Skip(substream.GetSize());
                break;
            }
                
            // Characters
            case ESMTag::ACHR:
            {
                ESMStream substream(stream, header.Size);
                WorldObject obj(WorldObjectType::Character, header.Meta.AsRecord.FormID);
                
                if (obj.Parse(substream) == false) {
                    mLoadMessages.push_back("Error: invalid ACHR record");
                    return false;
                }
                
                cell.AddObject(childType, obj);
                break;
            }
                
            case ESMTag::GRUP:
            {
                if (ParseCellChildrenGroup(stream, header, block, subblock) == false) {
                    mLoadMessages.push_back("Error: unable to parse cell children");
                    return false;
                }
                
                break;
            }
                
            case ESMTag::NAVM:
            {
                ESMStream substream(stream, header.Size);
                
                substream.Skip(substream.GetSize());
                break;
            }
            
            case ESMTag::LAND:
            {
                ESMStream substream(stream, header.Size);
                uint32_t decompSize;
                
                substream.Read32(decompSize);
                
                const size_t sourceSize = header.Size - 4;
                
                mBuffer.reserve(sourceSize);
                mDecompressedBuffer.reserve(decompSize);
                
                substream.ReadRaw((char *)&mBuffer[0], sourceSize);
                
                if (ESMUtility::ZlibDecompress(mBuffer, mDecompressedBuffer, sourceSize, decompSize) == false) {
                    mLoadMessages.push_back("Error: unable to decompress zlib LAND data");
                    //TODO: There is a single land entry in FalloutNV.esm that appears corrupted, skip it
                    break;
                }

                //This is fairly unpleasant but functions
                std::stringstream dataStream;
                dataStream.rdbuf()->pubsetbuf(reinterpret_cast<char *>(&mDecompressedBuffer[0]), decompSize);
                
                ESMStream decompressedStream(stream, dataStream, decompSize);
                
                LandDefinition landDefinition(header.Meta.AsRecord.FormID);
                
                if (landDefinition.Parse(decompressedStream) == false) {
                    mLoadMessages.push_back("Error: invalid LAND record");
                    return false;
                }
                
                cell.SetLandscapeID(header.Meta.AsRecord.FormID);
                mLandscapes.insert(std::pair<FormIdentifier, LandDefinition>(header.Meta.AsRecord.FormID, std::move(landDefinition)));
                break;
            }
            
            default:
                std::cout << "Found unhandled tag: " << ESMUtility::TagToString(header.Tag) << " " << header.Size << std::endl;
                break;
        }
        
        
    }
    
    return true;
}